aboutsummaryrefslogtreecommitdiff
path: root/pd/src/m_binbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'pd/src/m_binbuf.c')
-rw-r--r--pd/src/m_binbuf.c1138
1 files changed, 1138 insertions, 0 deletions
diff --git a/pd/src/m_binbuf.c b/pd/src/m_binbuf.c
new file mode 100644
index 00000000..6ff79e93
--- /dev/null
+++ b/pd/src/m_binbuf.c
@@ -0,0 +1,1138 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+
+/* IOhannes :
+ * changed the canvas_restore in "g_canvas.c", so that it might accept $args as well (like "pd $0_test")
+ * so you can make multiple & distinguishable templates
+ * 1511:forum::für::umläute:2001
+ * change marked with IOhannes
+ */
+
+#include <stdlib.h>
+#include "m_pd.h"
+#include <stdio.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#ifdef NT
+#include <io.h>
+#endif
+#include <fcntl.h>
+#include <string.h>
+#include <stdarg.h>
+
+struct _binbuf
+{
+ int b_n;
+ t_atom *b_vec;
+};
+
+t_binbuf *binbuf_new(void)
+{
+ t_binbuf *x = (t_binbuf *)t_getbytes(sizeof(*x));
+ x->b_n = 0;
+ x->b_vec = t_getbytes(0);
+ return (x);
+}
+
+void binbuf_free(t_binbuf *x)
+{
+ t_freebytes(x->b_vec, x->b_n * sizeof(*x->b_vec));
+ t_freebytes(x, sizeof(*x));
+}
+
+void binbuf_clear(t_binbuf *x)
+{
+ x->b_vec = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec), 0);
+ x->b_n = 0;
+}
+
+ /* convert text to a binbuf */
+void binbuf_text(t_binbuf *x, char *text, size_t size)
+{
+ char buf[MAXPDSTRING+1], *bufp, *ebuf = buf+MAXPDSTRING;
+ const char *textp = text, *etext = text+size;
+ t_atom *ap;
+ int nalloc = 16, natom = 0;
+ t_freebytes(x->b_vec, x->b_n * sizeof(*x->b_vec));
+ x->b_vec = t_getbytes(nalloc * sizeof(*x->b_vec));
+ ap = x->b_vec;
+ x->b_n = 0;
+ while (1)
+ {
+ int type;
+ /* skip leading space */
+ while ((textp != etext) && (*textp == ' ' || *textp == '\n'
+ || *textp == '\r' || *textp == '\t')) textp++;
+ if (textp == etext) break;
+ if (*textp == ';') SETSEMI(ap), textp++;
+ else if (*textp == ',') SETCOMMA(ap), textp++;
+ else
+ {
+ /* it's an atom other than a comma or semi */
+ char c;
+ int floatstate = 0, slash = 0, lastslash = 0,
+ firstslash = (*textp == '\\');
+ bufp = buf;
+ do
+ {
+ c = *bufp = *textp++;
+ lastslash = slash;
+ slash = (c == '\\');
+
+ if (floatstate >= 0)
+ {
+ int digit = (c >= '0' && c <= '9'),
+ dot = (c == '.'), minus = (c == '-'),
+ plusminus = (minus || (c == '+')),
+ expon = (c == 'e' || c == 'E');
+ if (floatstate == 0) /* beginning */
+ {
+ if (minus) floatstate = 1;
+ else if (digit) floatstate = 2;
+ else if (dot) floatstate = 3;
+ else floatstate = -1;
+ }
+ else if (floatstate == 1) /* got minus */
+ {
+ if (digit) floatstate = 2;
+ else if (dot) floatstate = 3;
+ else floatstate = -1;
+ }
+ else if (floatstate == 2) /* got digits */
+ {
+ if (dot) floatstate = 4;
+ else if (expon) floatstate = 6;
+ else if (!digit) floatstate = -1;
+ }
+ else if (floatstate == 3) /* got '.' without digits */
+ {
+ if (digit) floatstate = 5;
+ else floatstate = -1;
+ }
+ else if (floatstate == 4) /* got '.' after digits */
+ {
+ if (digit) floatstate = 5;
+ else if (expon) floatstate = 6;
+ else floatstate = -1;
+ }
+ else if (floatstate == 5) /* got digits after . */
+ {
+ if (expon) floatstate = 6;
+ else if (!digit) floatstate = -1;
+ }
+ else if (floatstate == 6) /* got 'e' */
+ {
+ if (plusminus) floatstate = 7;
+ else if (digit) floatstate = 8;
+ else floatstate = -1;
+ }
+ else if (floatstate == 7) /* got plus or minus */
+ {
+ if (digit) floatstate = 8;
+ else floatstate = -1;
+ }
+ else if (floatstate == 8) /* got digits */
+ {
+ if (!digit) floatstate = -1;
+ }
+ }
+ if (!slash) bufp++;
+ }
+ while (textp != etext && bufp != ebuf &&
+ (slash || (*textp != ' ' && *textp != '\n' && *textp != '\r'
+ && *textp != '\t' &&*textp != ',' && *textp != ';')));
+ *bufp = 0;
+#if 0
+ post("buf %s", buf);
+#endif
+ if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9' && !firstslash)
+ {
+ for (bufp = buf+2; *bufp; bufp++)
+ if (*bufp < '0' || *bufp > '9')
+ {
+ SETDOLLSYM(ap, gensym(buf+1));
+ goto didit;
+ }
+ SETDOLLAR(ap, atoi(buf+1));
+ didit: ;
+ }
+ else
+ {
+ if (floatstate == 2 || floatstate == 4 || floatstate == 5 ||
+ floatstate == 8)
+ SETFLOAT(ap, atof(buf));
+ else SETSYMBOL(ap, gensym(buf));
+ }
+ }
+ ap++;
+ natom++;
+ if (natom == nalloc)
+ {
+ x->b_vec = t_resizebytes(x->b_vec, nalloc * sizeof(*x->b_vec),
+ nalloc * (2*sizeof(*x->b_vec)));
+ nalloc = nalloc * 2;
+ ap = x->b_vec + natom;
+ }
+ if (textp == etext) break;
+ }
+ /* reallocate the vector to exactly the right size */
+ x->b_vec = t_resizebytes(x->b_vec, nalloc * sizeof(*x->b_vec),
+ natom * sizeof(*x->b_vec));
+ x->b_n = natom;
+}
+
+ /* convert a binbuf to text; no null termination. */
+void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp)
+{
+ char *buf = getbytes(0), *newbuf;
+ int length = 0;
+ char string[MAXPDSTRING];
+ t_atom *ap;
+ int indx;
+
+ for (ap = x->b_vec, indx = x->b_n; indx--; ap++)
+ {
+ int newlength;
+ if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) &&
+ length && buf[length-1] == ' ') length--;
+ atom_string(ap, string, MAXPDSTRING);
+ newlength = length + strlen(string) + 1;
+ if (!(newbuf = resizebytes(buf, length, newlength))) break;
+ buf = newbuf;
+ strcpy(buf + length, string);
+ length = newlength;
+ if (ap->a_type == A_SEMI) buf[length-1] = '\n';
+ else buf[length-1] = ' ';
+ }
+ if (length && buf[length-1] == ' ')
+ {
+ if (newbuf = t_resizebytes(buf, length, length-1))
+ {
+ buf = newbuf;
+ length--;
+ }
+ }
+ *bufp = buf;
+ *lengthp = length;
+}
+
+/* LATER improve the out-of-space behavior below. Also fix this so that
+writing to file doesn't buffer everything together. */
+
+void binbuf_add(t_binbuf *x, int argc, t_atom *argv)
+{
+ int newsize = x->b_n + argc, i;
+ t_atom *ap;
+ if (ap = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec),
+ newsize * sizeof(*x->b_vec)))
+ x->b_vec = ap;
+ else
+ {
+ error("binbuf_addmessage: out of space");
+ return;
+ }
+#if 0
+ startpost("binbuf_add: ");
+ postatom(argc, argv);
+ endpost();
+#endif
+ for (ap = x->b_vec + x->b_n, i = argc; i--; ap++)
+ *ap = *(argv++);
+ x->b_n = newsize;
+}
+
+#define MAXADDMESSV 100
+void binbuf_addv(t_binbuf *x, char *fmt, ...)
+{
+ va_list ap;
+ t_atom arg[MAXADDMESSV], *at =arg;
+ int nargs = 0;
+ char *fp = fmt;
+
+ va_start(ap, fmt);
+ while (1)
+ {
+ if (nargs >= MAXADDMESSV)
+ {
+ error("binbuf_addmessv: only %d allowed", MAXADDMESSV);
+ break;
+ }
+ switch(*fp++)
+ {
+ case 'i': SETFLOAT(at, va_arg(ap, t_int)); break;
+ case 'f': SETFLOAT(at, va_arg(ap, double)); break;
+ case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break;
+ case ';': SETSEMI(at); break;
+ case ',': SETCOMMA(at); break;
+ default: goto done;
+ }
+ at++;
+ nargs++;
+ }
+done:
+ va_end(ap);
+ binbuf_add(x, nargs, arg);
+}
+
+/* add a binbuf to another one for saving. Semicolons and commas go to
+symbols ";", "'",; the symbol ";" goes to "\;", etc. */
+
+void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y)
+{
+ t_binbuf *z = binbuf_new();
+ int i;
+ t_atom *ap;
+ binbuf_add(z, y->b_n, y->b_vec);
+ for (i = 0, ap = z->b_vec; i < z->b_n; i++, ap++)
+ {
+ char tbuf[MAXPDSTRING];
+ switch (ap->a_type)
+ {
+ case A_FLOAT:
+ break;
+ case A_SEMI:
+ SETSYMBOL(ap, gensym(";"));
+ break;
+ case A_COMMA:
+ SETSYMBOL(ap, gensym(","));
+ break;
+ case A_DOLLAR:
+ sprintf(tbuf, "$%d", ap->a_w.w_index);
+ SETSYMBOL(ap, gensym(tbuf));
+ break;
+ case A_DOLLSYM:
+ sprintf(tbuf, "$%s", ap->a_w.w_symbol->s_name);
+ SETSYMBOL(ap, gensym(tbuf));
+ break;
+ case A_SYMBOL:
+ /* FIXME make this general */
+ if (!strcmp(ap->a_w.w_symbol->s_name, ";"))
+ SETSYMBOL(ap, gensym(";"));
+ else if (!strcmp(ap->a_w.w_symbol->s_name, ","))
+ SETSYMBOL(ap, gensym(","));
+ break;
+ default:
+ bug("binbuf_addbinbuf");
+ }
+ }
+
+ binbuf_add(x, z->b_n, z->b_vec);
+}
+
+void binbuf_addsemi(t_binbuf *x)
+{
+ t_atom a;
+ SETSEMI(&a);
+ binbuf_add(x, 1, &a);
+}
+
+/* Supply atoms to a binbuf from a message, making the opposite changes
+from binbuf_addbinbuf. The symbol ";" goes to a semicolon, etc. */
+
+void binbuf_restore(t_binbuf *x, int argc, t_atom *argv)
+{
+ int newsize = x->b_n + argc, i;
+ t_atom *ap;
+ if (ap = t_resizebytes(x->b_vec, x->b_n * sizeof(*x->b_vec),
+ newsize * sizeof(*x->b_vec)))
+ x->b_vec = ap;
+ else
+ {
+ error("binbuf_addmessage: out of space");
+ return;
+ }
+
+ for (ap = x->b_vec + x->b_n, i = argc; i--; ap++)
+ {
+ if (argv->a_type == A_SYMBOL)
+ {
+ char *str = argv->a_w.w_symbol->s_name;
+ if (!strcmp(str, ";")) SETSEMI(ap);
+ else if (!strcmp(str, ",")) SETCOMMA(ap);
+ else if (str[0] == '$' && str[1] >= '0' && str[1] <= '9')
+ {
+ int dollsym = 0;
+ char *str2;
+ for (str2 = str + 2; *str2; str2++)
+ if (*str2 < '0' || *str2 > '9')
+ dollsym = 1;
+ if (dollsym)
+ SETDOLLSYM(ap, gensym(str + 1));
+ else
+ {
+ int dollar = 0;
+ sscanf(argv->a_w.w_symbol->s_name + 1, "%d", &dollar);
+ SETDOLLAR(ap, dollar);
+ }
+ }
+ else *ap = *argv;
+ argv++;
+ }
+ else *ap = *(argv++);
+ }
+ x->b_n = newsize;
+}
+
+
+#define MSTACKSIZE 2048
+
+void binbuf_print(t_binbuf *x)
+{
+ int i, startedpost = 0, newline = 1;
+ for (i = 0; i < x->b_n; i++)
+ {
+ if (newline)
+ {
+ if (startedpost) endpost();
+ startpost("");
+ startedpost = 1;
+ }
+ postatom(1, x->b_vec + i);
+ if (x->b_vec[i].a_type == A_SEMI)
+ newline = 1;
+ else newline = 0;
+ }
+ if (startedpost) endpost();
+}
+
+int binbuf_getnatom(t_binbuf *x)
+{
+ return (x->b_n);
+}
+
+t_atom *binbuf_getvec(t_binbuf *x)
+{
+ return (x->b_vec);
+}
+
+int canvas_getdollarzero( void);
+
+t_symbol *realizedollsym(t_symbol *s, int ac, t_atom *av, int tonew) /* IOhannes: not static any more */
+{
+ int argno = atol(s->s_name), lastnum;
+ char buf[MAXPDSTRING], c, *sp;
+ for (lastnum = 0, sp = s->s_name; ((c = *sp) && c >= '0' && c <= '9');
+ sp++, lastnum++)
+ if (!c || argno < 0 || argno > ac)
+ {
+ if (!tonew)
+ return (0);
+ else sprintf(buf, "$%d", argno);
+ }
+ else if (argno == 0)
+ sprintf(buf, "%d", canvas_getdollarzero());
+ else
+ atom_string(av+(argno-1), buf, MAXPDSTRING/2-1);
+ strncat(buf, sp, MAXPDSTRING/2-1);
+ return (gensym(buf));
+}
+
+void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv)
+{
+ static t_atom mstack[MSTACKSIZE], *msp = mstack, *ems = mstack+MSTACKSIZE;
+ t_atom *stackwas = msp;
+ t_atom *at = x->b_vec;
+ int ac = x->b_n;
+ int nargs;
+
+ while (1)
+ {
+ t_pd *nexttarget;
+ /* get a target. */
+ while (!target)
+ {
+ t_symbol *s;
+ while (ac && (at->a_type == A_SEMI || at->a_type == A_COMMA))
+ ac--, at++;
+ if (!ac) break;
+ if (at->a_type == A_DOLLAR)
+ {
+ if (at->a_w.w_index <= 0 || at->a_w.w_index > argc)
+ {
+ error("$%d: not enough arguments supplied",
+ at->a_w.w_index);
+ goto cleanup;
+ }
+ else if (argv[at->a_w.w_index-1].a_type != A_SYMBOL)
+ {
+ error("$%d: symbol needed as message destination",
+ at->a_w.w_index);
+ goto cleanup;
+ }
+ else s = argv[at->a_w.w_index-1].a_w.w_symbol;
+ }
+ else if (at->a_type == A_DOLLSYM)
+ {
+ if (!(s = realizedollsym(at->a_w.w_symbol, argc, argv, 0)))
+ {
+ error("$%s: not enough arguments supplied",
+ at->a_w.w_symbol->s_name);
+ goto cleanup;
+ }
+ }
+ else s = atom_getsymbol(at);
+ if (!(target = s->s_thing))
+ {
+ error("%s: no such object", s->s_name);
+ cleanup:
+ do at++, ac--;
+ while (ac && at->a_type != A_SEMI);
+ /* LATER eat args until semicolon and continue */
+ continue;
+ }
+ else
+ {
+ at++, ac--;
+ break;
+ }
+ }
+ if (!ac) break;
+ nargs = 0;
+ nexttarget = target;
+ while (1)
+ {
+ t_symbol *s9;
+ if (!ac) goto gotmess;
+ if (msp >= ems)
+ {
+ error("message stack overflow");
+ goto broken;
+ }
+ switch (at->a_type)
+ {
+ case A_SEMI:
+ /* semis and commas in new message just get bashed to
+ a symbol. This is needed so you can pass them to "expr." */
+ if (target == &pd_objectmaker)
+ {
+ SETSYMBOL(msp, gensym(";"));
+ break;
+ }
+ else
+ {
+ nexttarget = 0;
+ goto gotmess;
+ }
+ case A_COMMA:
+ if (target == &pd_objectmaker)
+ {
+ SETSYMBOL(msp, gensym(","));
+ break;
+ }
+ else goto gotmess;
+ case A_FLOAT:
+ case A_SYMBOL:
+ *msp = *at;
+ break;
+ case A_DOLLAR:
+ if (at->a_w.w_index > 0 && at->a_w.w_index <= argc)
+ *msp = argv[at->a_w.w_index-1];
+ else if (at->a_w.w_index == 0)
+ SETFLOAT(msp, canvas_getdollarzero());
+ else
+ {
+ if (target == &pd_objectmaker)
+ SETFLOAT(msp, 0);
+ else
+ {
+ error("$%d: argument number out of range",
+ at->a_w.w_index);
+ SETFLOAT(msp, 0);
+ }
+ }
+ break;
+ case A_DOLLSYM:
+ s9 = realizedollsym(at->a_w.w_symbol, argc, argv,
+ target == &pd_objectmaker);
+ if (!s9)
+ goto broken;
+ SETSYMBOL(msp, s9);
+ break;
+ default:
+ bug("bad item in binbuf");
+ goto broken;
+ }
+ msp++;
+ ac--;
+ at++;
+ nargs++;
+ }
+ gotmess:
+ if (nargs)
+ {
+ switch (stackwas->a_type)
+ {
+ case A_SYMBOL:
+ typedmess(target, stackwas->a_w.w_symbol, nargs-1, stackwas+1);
+ break;
+ case A_FLOAT:
+ if (nargs == 1) pd_float(target, stackwas->a_w.w_float);
+ else pd_list(target, 0, nargs, stackwas);
+ break;
+ }
+ }
+ msp = stackwas;
+ if (!ac) break;
+ target = nexttarget;
+ at++;
+ ac--;
+ }
+
+ return;
+broken:
+ msp = stackwas;
+}
+
+static int binbuf_doopen(char *s, int mode)
+{
+ char namebuf[MAXPDSTRING];
+#ifdef NT
+ mode |= O_BINARY;
+#endif
+ sys_bashfilename(s, namebuf);
+ return (open(namebuf, mode));
+}
+
+static FILE *binbuf_dofopen(char *s, char *mode)
+{
+ char namebuf[MAXPDSTRING];
+ sys_bashfilename(s, namebuf);
+ return (fopen(namebuf, mode));
+}
+
+int binbuf_read(t_binbuf *b, char *filename, char *dirname, int crflag)
+{
+ long length;
+ int fd;
+ int readret;
+ char *buf;
+ char namebuf[MAXPDSTRING];
+
+ namebuf[0] = 0;
+ if (*dirname)
+ strcat(namebuf, dirname), strcat(namebuf, "/");
+ strcat(namebuf, filename);
+
+ if ((fd = binbuf_doopen(namebuf, 0)) < 0)
+ {
+ fprintf(stderr, "open: ");
+ perror(namebuf);
+ return (1);
+ }
+ if ((length = lseek(fd, 0, SEEK_END)) < 0 || lseek(fd, 0, SEEK_SET) < 0
+ || !(buf = t_getbytes(length)))
+ {
+ fprintf(stderr, "lseek: ");
+ perror(namebuf);
+ close(fd);
+ return(1);
+ }
+ if ((readret = read(fd, buf, length)) < length)
+ {
+ fprintf(stderr, "read (%d %ld) -> %d\n", fd, length, readret);
+ perror(namebuf);
+ close(fd);
+ t_freebytes(buf, length);
+ return(1);
+ }
+ /* optionally map carriage return to semicolon */
+ if (crflag)
+ {
+ int i;
+ for (i = 0; i < length; i++)
+ if (buf[i] == '\n')
+ buf[i] = ';';
+ }
+ binbuf_text(b, buf, length);
+
+#if 0
+ startpost("binbuf_read "); postatom(b->b_n, b->b_vec); endpost();
+#endif
+
+ t_freebytes(buf, length);
+ close(fd);
+ return (0);
+}
+
+int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname,
+ int crflag)
+{
+ int filedesc;
+ char buf[MAXPDSTRING], *bufptr;
+ if ((filedesc = open_via_path(
+ dirname, filename, "", buf, &bufptr, MAXPDSTRING, 0)) < 0)
+ {
+ error("%s: can't open", filename);
+ return (1);
+ }
+ else close (filedesc);
+ if (binbuf_read(b, bufptr, buf, crflag))
+ return (1);
+ else return (0);
+}
+
+#define WBUFSIZE 4096
+static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd);
+
+ /* write a binbuf to a text file. If "crflag" is set we suppress
+ semicolons. */
+int binbuf_write(t_binbuf *x, char *filename, char *dir, int crflag)
+{
+ FILE *f = 0;
+ char sbuf[WBUFSIZE], fbuf[MAXPDSTRING], *bp = sbuf, *ep = sbuf + WBUFSIZE;
+ t_atom *ap;
+ int indx, deleteit = 0;
+ int ncolumn = 0;
+
+ fbuf[0] = 0;
+ if (*dir)
+ strcat(fbuf, dir), strcat(fbuf, "/");
+ strcat(fbuf, filename);
+ if (!strcmp(filename + strlen(filename) - 4, ".pat"))
+ {
+ x = binbuf_convert(x, 0);
+ deleteit = 1;
+ }
+
+ if (!(f = binbuf_dofopen(fbuf, "w")))
+ {
+ fprintf(stderr, "open: ");
+ sys_unixerror(fbuf);
+ goto fail;
+ }
+ for (ap = x->b_vec, indx = x->b_n; indx--; ap++)
+ {
+ int length;
+ /* estimate how many characters will be needed. Printing out
+ symbols may need extra characters for inserting backslashes. */
+ if (ap->a_type == A_SYMBOL || ap->a_type == A_DOLLSYM)
+ length = 80 + strlen(ap->a_w.w_symbol->s_name);
+ else length = 40;
+ if (ep - bp < length)
+ {
+ if (fwrite(sbuf, bp-sbuf, 1, f) < 1)
+ {
+ sys_unixerror(fbuf);
+ goto fail;
+ }
+ bp = sbuf;
+ }
+ if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) &&
+ bp > sbuf && bp[-1] == ' ') bp--;
+ if (!crflag || ap->a_type != A_SEMI)
+ {
+ atom_string(ap, bp, (ep-bp)-2);
+ length = strlen(bp);
+ bp += length;
+ ncolumn += length;
+ }
+ if (ap->a_type == A_SEMI || ncolumn > 65)
+ {
+ *bp++ = '\n';
+ ncolumn = 0;
+ }
+ else
+ {
+ *bp++ = ' ';
+ ncolumn++;
+ }
+ }
+ if (fwrite(sbuf, bp-sbuf, 1, f) < 1)
+ {
+ sys_unixerror(fbuf);
+ goto fail;
+ }
+ if (deleteit)
+ binbuf_free(x);
+ fclose(f);
+ return (0);
+fail:
+ if (deleteit)
+ binbuf_free(x);
+ if (f)
+ fclose(f);
+ return (1);
+}
+
+/* The following routine attempts to convert from max to pd or back. The
+max to pd direction is working OK but you will need to make lots of
+abstractions for objects like "gate" which don't exist in Pd. conversion
+from Pd to Max hasn't been tested for patches with subpatches yet! */
+
+#define MAXSTACK 1000
+
+#define ISSYMBOL(a, b) ((a)->a_type == A_SYMBOL && \
+ !strcmp((a)->a_w.w_symbol->s_name, (b)))
+
+static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd)
+{
+ t_binbuf *newb = binbuf_new();
+ t_atom *vec = oldb->b_vec;
+ t_int n = oldb->b_n, nextindex, stackdepth = 0, stack[MAXSTACK],
+ nobj = 0, i;
+ t_atom outmess[MAXSTACK], *nextmess;
+ if (!maxtopd)
+ binbuf_addv(newb, "ss;", gensym("max"), gensym("v2"));
+ for (nextindex = 0; nextindex < n; )
+ {
+ int endmess, natom;
+ char *first, *second;
+ for (endmess = nextindex; endmess < n && vec[endmess].a_type != A_SEMI;
+ endmess++)
+ ;
+ if (endmess == n) break;
+ if (endmess == nextindex || endmess == nextindex + 1
+ || vec[nextindex].a_type != A_SYMBOL ||
+ vec[nextindex+1].a_type != A_SYMBOL)
+ {
+ nextindex = endmess + 1;
+ continue;
+ }
+ natom = endmess - nextindex;
+ if (natom > MAXSTACK-10) natom = MAXSTACK-10;
+ nextmess = vec + nextindex;
+ first = nextmess->a_w.w_symbol->s_name;
+ second = (nextmess+1)->a_w.w_symbol->s_name;
+ if (maxtopd)
+ {
+ /* case 1: importing a ".pat" file into Pd. */
+
+ /* dollar signs in file translate to symbols */
+ for (i = 0; i < natom; i++)
+ {
+ if (nextmess[i].a_type == A_DOLLAR)
+ {
+ char buf[100];
+ sprintf(buf, "$%d", nextmess[i].a_w.w_index);
+ SETSYMBOL(nextmess+i, gensym(buf));
+ }
+ else if (nextmess[i].a_type == A_DOLLSYM)
+ {
+ char buf[100];
+ sprintf(buf, "$%s", nextmess[i].a_w.w_symbol->s_name);
+ SETSYMBOL(nextmess+i, gensym(buf));
+ }
+ }
+ if (!strcmp(first, "#N"))
+ {
+ if (!strcmp(second, "vpatcher"))
+ {
+ if (stackdepth >= MAXSTACK)
+ {
+ post("too many embedded patches");
+ return (newb);
+ }
+ stack[stackdepth] = nobj;
+ stackdepth++;
+ nobj = 0;
+ binbuf_addv(newb, "ssfffff;",
+ gensym("#N"), gensym("canvas"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ atom_getfloatarg(4, natom, nextmess) -
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(5, natom, nextmess) -
+ atom_getfloatarg(3, natom, nextmess),
+ 12.);
+ }
+ }
+ if (!strcmp(first, "#P"))
+ {
+ if (natom >= 7 && !strcmp(second, "newobj")
+ && (ISSYMBOL(&nextmess[6], "patcher") ||
+ ISSYMBOL(&nextmess[6], "p")))
+ {
+ binbuf_addv(newb, "ssffss;",
+ gensym("#X"), gensym("restore"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ gensym("pd"), atom_getsymbolarg(7, natom, nextmess));
+ if (stackdepth) stackdepth--;
+ nobj = stack[stackdepth];
+ nobj++;
+ }
+ else if (!strcmp(second, "newex") || !strcmp(second, "newobj"))
+ {
+ t_symbol *classname =
+ atom_getsymbolarg(6, natom, nextmess);
+ if (classname == gensym("trigger") ||
+ classname == gensym("t"))
+ {
+ for (i = 7; i < natom; i++)
+ if (nextmess[i].a_type == A_SYMBOL &&
+ nextmess[i].a_w.w_symbol == gensym("i"))
+ nextmess[i].a_w.w_symbol = gensym("f");
+ }
+ SETSYMBOL(outmess, gensym("#X"));
+ SETSYMBOL(outmess + 1, gensym("obj"));
+ outmess[2] = nextmess[2];
+ outmess[3] = nextmess[3];
+ for (i = 6; i < natom; i++)
+ outmess[i-2] = nextmess[i];
+ SETSEMI(outmess + natom - 2);
+ binbuf_add(newb, natom - 1, outmess);
+ nobj++;
+ }
+ else if (!strcmp(second, "message") ||
+ !strcmp(second, "comment"))
+ {
+ SETSYMBOL(outmess, gensym("#X"));
+ SETSYMBOL(outmess + 1, gensym(
+ (strcmp(second, "message") ? "text" : "msg")));
+ outmess[2] = nextmess[2];
+ outmess[3] = nextmess[3];
+ for (i = 6; i < natom; i++)
+ outmess[i-2] = nextmess[i];
+ SETSEMI(outmess + natom - 2);
+ binbuf_add(newb, natom - 1, outmess);
+ nobj++;
+ }
+ else if (!strcmp(second, "button"))
+ {
+ binbuf_addv(newb, "ssffs;",
+ gensym("#X"), gensym("msg"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ gensym("bang"));
+ nobj++;
+ }
+ else if (!strcmp(second, "slider") || !strcmp(second, "number")
+ || !strcmp(second, "flonum") || !strcmp(second, "toggle"))
+ {
+ binbuf_addv(newb, "ssff;",
+ gensym("#X"), gensym("floatatom"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess));
+ nobj++;
+ }
+ else if (!strcmp(second, "inlet"))
+ {
+ binbuf_addv(newb, "ssffs;",
+ gensym("#X"), gensym("obj"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ gensym((natom > 5 ? "inlet~" : "inlet")));
+ nobj++;
+ }
+ else if (!strcmp(second, "outlet"))
+ {
+ binbuf_addv(newb, "ssffs;",
+ gensym("#X"), gensym("obj"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ gensym((natom > 5 ? "outlet~" : "outlet")));
+ nobj++;
+ }
+ else if (!strcmp(second, "connect")||
+ !strcmp(second, "fasten"))
+ {
+ binbuf_addv(newb, "ssffff;",
+ gensym("#X"), gensym("connect"),
+ nobj - atom_getfloatarg(2, natom, nextmess) - 1,
+ atom_getfloatarg(3, natom, nextmess),
+ nobj - atom_getfloatarg(4, natom, nextmess) - 1,
+ atom_getfloatarg(5, natom, nextmess));
+ }
+ }
+ }
+ else /* Pd to Max */
+ {
+ if (!strcmp(first, "#N"))
+ {
+ if (!strcmp(second, "canvas"))
+ {
+ if (stackdepth >= MAXSTACK)
+ {
+ post("too many embedded patches");
+ return (newb);
+ }
+ stack[stackdepth] = nobj;
+ stackdepth++;
+ nobj = 0;
+ binbuf_addv(newb, "ssffff;",
+ gensym("#N"), gensym("vpatcher"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ atom_getfloatarg(4, natom, nextmess),
+ atom_getfloatarg(5, natom, nextmess));
+ }
+ }
+ if (!strcmp(first, "#X"))
+ {
+ if (natom >= 5 && !strcmp(second, "restore")
+ && (ISSYMBOL (&nextmess[4], "pd")))
+ {
+ binbuf_addv(newb, "ss;", gensym("#P"), gensym("pop"));
+ binbuf_addv(newb, "ssffffss;",
+ gensym("#P"), gensym("newobj"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess), 50., 1.,
+ gensym("patcher"),
+ atom_getsymbolarg(5, natom, nextmess));
+ if (stackdepth) stackdepth--;
+ nobj = stack[stackdepth];
+ nobj++;
+ }
+ else if (!strcmp(second, "obj"))
+ {
+ t_symbol *classname =
+ atom_getsymbolarg(4, natom, nextmess);
+ if (classname == gensym("inlet"))
+ binbuf_addv(newb, "ssfff;", gensym("#P"),
+ gensym("inlet"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ 15.);
+ else if (classname == gensym("inlet~"))
+ binbuf_addv(newb, "ssffff;", gensym("#P"),
+ gensym("inlet"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ 15., 1.);
+ else if (classname == gensym("outlet"))
+ binbuf_addv(newb, "ssfff;", gensym("#P"),
+ gensym("outlet"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ 15.);
+ else if (classname == gensym("outlet~"))
+ binbuf_addv(newb, "ssffff;", gensym("#P"),
+ gensym("outlet"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ 15., 1.);
+ else
+ {
+ SETSYMBOL(outmess, gensym("#P"));
+ SETSYMBOL(outmess + 1, gensym("newex"));
+ outmess[2] = nextmess[2];
+ outmess[3] = nextmess[3];
+ SETFLOAT(outmess + 4, 50);
+ SETFLOAT(outmess + 5, 1);
+ for (i = 4; i < natom; i++)
+ outmess[i+2] = nextmess[i];
+ SETSEMI(outmess + natom + 2);
+ binbuf_add(newb, natom + 3, outmess);
+ }
+ nobj++;
+
+ }
+ else if (!strcmp(second, "msg") ||
+ !strcmp(second, "text"))
+ {
+ SETSYMBOL(outmess, gensym("#P"));
+ SETSYMBOL(outmess + 1, gensym(
+ (strcmp(second, "msg") ? "comment" : "message")));
+ outmess[2] = nextmess[2];
+ outmess[3] = nextmess[3];
+ SETFLOAT(outmess + 4, 50);
+ SETFLOAT(outmess + 5, 1);
+ for (i = 4; i < natom; i++)
+ outmess[i+2] = nextmess[i];
+ SETSEMI(outmess + natom + 2);
+ binbuf_add(newb, natom + 3, outmess);
+ nobj++;
+ }
+ else if (!strcmp(second, "floatatom"))
+ {
+ binbuf_addv(newb, "ssfff;",
+ gensym("#P"), gensym("flonum"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess), 35);
+ nobj++;
+ }
+ else if (!strcmp(second, "connect"))
+ {
+ binbuf_addv(newb, "ssffff;",
+ gensym("#P"), gensym("connect"),
+ nobj - atom_getfloatarg(2, natom, nextmess) - 1,
+ atom_getfloatarg(3, natom, nextmess),
+ nobj - atom_getfloatarg(4, natom, nextmess) - 1,
+ atom_getfloatarg(5, natom, nextmess));
+ }
+ }
+ }
+ nextindex = endmess + 1;
+ }
+ if (!maxtopd)
+ binbuf_addv(newb, "ss;", gensym("#P"), gensym("pop"));
+#if 1
+ binbuf_write(newb, "import-result.pd", "/tmp", 0);
+#endif
+ return (newb);
+}
+
+ /* function to support searching */
+int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf)
+{
+ int indexin, nmatched;
+ for (indexin = 0; indexin <= inbuf->b_n - searchbuf->b_n; indexin++)
+ {
+ for (nmatched = 0; nmatched < searchbuf->b_n; nmatched++)
+ {
+ t_atom *a1 = &inbuf->b_vec[indexin + nmatched],
+ *a2 = &searchbuf->b_vec[nmatched];
+ if (a1->a_type != a2->a_type ||
+ a1->a_type == A_SYMBOL && a1->a_w.w_symbol != a2->a_w.w_symbol
+ ||
+ a1->a_type == A_FLOAT && a1->a_w.w_float != a2->a_w.w_float
+ ||
+ a1->a_type == A_DOLLAR && a1->a_w.w_index != a2->a_w.w_index
+ ||
+ a1->a_type == A_DOLLSYM && a1->a_w.w_symbol != a2->a_w.w_symbol)
+ goto nomatch;
+ }
+ return (1);
+ nomatch: ;
+ }
+ return (0);
+}
+
+void pd_doloadbang(void);
+
+/* LATER make this evaluate the file on-the-fly. */
+/* LATER figure out how to log errors */
+void binbuf_evalfile(t_symbol *name, t_symbol *dir)
+{
+ t_binbuf *b = binbuf_new();
+ int import = !strcmp(name->s_name + strlen(name->s_name) - 4, ".pat");
+ /* set filename so that new canvases can pick them up */
+ int dspstate = canvas_suspend_dsp();
+ glob_setfilename(0, name, dir);
+ if (binbuf_read(b, name->s_name, dir->s_name, 0))
+ {
+ perror(name->s_name);
+ }
+ else
+ {
+ if (import)
+ {
+ t_binbuf *newb = binbuf_convert(b, 1);
+ binbuf_free(b);
+ b = newb;
+ }
+ binbuf_eval(b, 0, 0, 0);
+ }
+ glob_setfilename(0, &s_, &s_); /* bug fix by Krzysztof Czaja */
+ binbuf_free(b);
+ canvas_resume_dsp(dspstate);
+}
+
+void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir)
+{
+ t_pd *x = 0;
+ /* even though binbuf_evalfile appears to take care of dspstate,
+ we have to do it again here, because canvas_startdsp() assumes
+ that all toplevel canvases are visible. LATER check if this
+ is still necessary -- probably not. */
+
+ int dspstate = canvas_suspend_dsp();
+ binbuf_evalfile(name, dir);
+ while ((x != s__X.s_thing) && (x = s__X.s_thing))
+ vmess(x, gensym("pop"), "i", 1);
+ pd_doloadbang();
+ canvas_resume_dsp(dspstate);
+}