aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/sam/mesg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/sam/mesg.c')
-rw-r--r--src/cmd/sam/mesg.c821
1 files changed, 821 insertions, 0 deletions
diff --git a/src/cmd/sam/mesg.c b/src/cmd/sam/mesg.c
new file mode 100644
index 00000000..189c11ac
--- /dev/null
+++ b/src/cmd/sam/mesg.c
@@ -0,0 +1,821 @@
+#include "sam.h"
+
+Header h;
+uchar indata[DATASIZE];
+uchar outdata[2*DATASIZE+3]; /* room for overflow message */
+uchar *inp;
+uchar *outp;
+uchar *outmsg = outdata;
+Posn cmdpt;
+Posn cmdptadv;
+Buffer snarfbuf;
+int waitack;
+int noflush;
+int tversion;
+
+long inlong(void);
+long invlong(void);
+int inshort(void);
+int inmesg(Tmesg);
+void setgenstr(File*, Posn, Posn);
+
+#ifdef DEBUG
+char *hname[] = {
+ [Hversion] "Hversion",
+ [Hbindname] "Hbindname",
+ [Hcurrent] "Hcurrent",
+ [Hnewname] "Hnewname",
+ [Hmovname] "Hmovname",
+ [Hgrow] "Hgrow",
+ [Hcheck0] "Hcheck0",
+ [Hcheck] "Hcheck",
+ [Hunlock] "Hunlock",
+ [Hdata] "Hdata",
+ [Horigin] "Horigin",
+ [Hunlockfile] "Hunlockfile",
+ [Hsetdot] "Hsetdot",
+ [Hgrowdata] "Hgrowdata",
+ [Hmoveto] "Hmoveto",
+ [Hclean] "Hclean",
+ [Hdirty] "Hdirty",
+ [Hcut] "Hcut",
+ [Hsetpat] "Hsetpat",
+ [Hdelname] "Hdelname",
+ [Hclose] "Hclose",
+ [Hsetsnarf] "Hsetsnarf",
+ [Hsnarflen] "Hsnarflen",
+ [Hack] "Hack",
+ [Hexit] "Hexit",
+ [Hplumb] "Hplumb",
+};
+
+char *tname[] = {
+ [Tversion] "Tversion",
+ [Tstartcmdfile] "Tstartcmdfile",
+ [Tcheck] "Tcheck",
+ [Trequest] "Trequest",
+ [Torigin] "Torigin",
+ [Tstartfile] "Tstartfile",
+ [Tworkfile] "Tworkfile",
+ [Ttype] "Ttype",
+ [Tcut] "Tcut",
+ [Tpaste] "Tpaste",
+ [Tsnarf] "Tsnarf",
+ [Tstartnewfile] "Tstartnewfile",
+ [Twrite] "Twrite",
+ [Tclose] "Tclose",
+ [Tlook] "Tlook",
+ [Tsearch] "Tsearch",
+ [Tsend] "Tsend",
+ [Tdclick] "Tdclick",
+ [Tstartsnarf] "Tstartsnarf",
+ [Tsetsnarf] "Tsetsnarf",
+ [Tack] "Tack",
+ [Texit] "Texit",
+ [Tplumb] "Tplumb",
+};
+
+void
+journal(int out, char *s)
+{
+ static int fd = 0;
+
+ if(fd <= 0)
+ fd = create("/tmp/sam.out", 1, 0666L);
+ fprint(fd, "%s%s\n", out? "out: " : "in: ", s);
+}
+
+void
+journaln(int out, long n)
+{
+ char buf[32];
+
+ sprint(buf, "%ld", n);
+ journal(out, buf);
+}
+#else
+#define journal(a, b)
+#define journaln(a, b)
+#endif
+
+int
+rcvchar(void){
+ static uchar buf[64];
+ static i, nleft = 0;
+
+ if(nleft <= 0){
+ nleft = read(0, (char *)buf, sizeof buf);
+ if(nleft <= 0)
+ return -1;
+ i = 0;
+ }
+ --nleft;
+ return buf[i++];
+}
+
+int
+rcv(void){
+ int c;
+ static state = 0;
+ static count = 0;
+ static i = 0;
+
+ while((c=rcvchar()) != -1)
+ switch(state){
+ case 0:
+ h.type = c;
+ state++;
+ break;
+
+ case 1:
+ h.count0 = c;
+ state++;
+ break;
+
+ case 2:
+ h.count1 = c;
+ count = h.count0|(h.count1<<8);
+ i = 0;
+ if(count > DATASIZE)
+ panic("count>DATASIZE");
+ if(count == 0)
+ goto zerocount;
+ state++;
+ break;
+
+ case 3:
+ indata[i++] = c;
+ if(i == count){
+ zerocount:
+ indata[i] = 0;
+ state = count = 0;
+ return inmesg(h.type);
+ }
+ break;
+ }
+ return 0;
+}
+
+File *
+whichfile(int tag)
+{
+ int i;
+
+ for(i = 0; i<file.nused; i++)
+ if(file.filepptr[i]->tag==tag)
+ return file.filepptr[i];
+ hiccough((char *)0);
+ return 0;
+}
+
+int
+inmesg(Tmesg type)
+{
+ Rune buf[1025];
+ char cbuf[64];
+ int i, m;
+ short s;
+ long l, l1;
+ File *f;
+ Posn p0, p1, p;
+ Range r;
+ String *str;
+ char *c, *wdir;
+ Rune *rp;
+ Plumbmsg *pm;
+
+ if(type > TMAX)
+ panic("inmesg");
+
+ journal(0, tname[type]);
+
+ inp = indata;
+ switch(type){
+ case -1:
+ panic("rcv error");
+
+ default:
+ fprint(2, "unknown type %d\n", type);
+ panic("rcv unknown");
+
+ case Tversion:
+ tversion = inshort();
+ journaln(0, tversion);
+ break;
+
+ case Tstartcmdfile:
+ l = invlong(); /* for 64-bit pointers */
+ journaln(0, l);
+ Strdupl(&genstr, samname);
+ cmd = newfile();
+ cmd->unread = 0;
+ outTsv(Hbindname, cmd->tag, l);
+ outTs(Hcurrent, cmd->tag);
+ logsetname(cmd, &genstr);
+ cmd->rasp = emalloc(sizeof(List));
+ cmd->mod = 0;
+ if(cmdstr.n){
+ loginsert(cmd, 0L, cmdstr.s, cmdstr.n);
+ Strdelete(&cmdstr, 0L, (Posn)cmdstr.n);
+ }
+ fileupdate(cmd, FALSE, TRUE);
+ outT0(Hunlock);
+ break;
+
+ case Tcheck:
+ /* go through whichfile to check the tag */
+ outTs(Hcheck, whichfile(inshort())->tag);
+ break;
+
+ case Trequest:
+ f = whichfile(inshort());
+ p0 = inlong();
+ p1 = p0+inshort();
+ journaln(0, p0);
+ journaln(0, p1-p0);
+ if(f->unread)
+ panic("Trequest: unread");
+ if(p1>f->_.nc)
+ p1 = f->_.nc;
+ if(p0>f->_.nc) /* can happen e.g. scrolling during command */
+ p0 = f->_.nc;
+ if(p0 == p1){
+ i = 0;
+ r.p1 = r.p2 = p0;
+ }else{
+ r = rdata(f->rasp, p0, p1-p0);
+ i = r.p2-r.p1;
+ bufread(f, r.p1, buf, i);
+ }
+ buf[i]=0;
+ outTslS(Hdata, f->tag, r.p1, tmprstr(buf, i+1));
+ break;
+
+ case Torigin:
+ s = inshort();
+ l = inlong();
+ l1 = inlong();
+ journaln(0, l1);
+ lookorigin(whichfile(s), l, l1);
+ break;
+
+ case Tstartfile:
+ termlocked++;
+ f = whichfile(inshort());
+ if(!f->rasp) /* this might be a duplicate message */
+ f->rasp = emalloc(sizeof(List));
+ current(f);
+ outTsv(Hbindname, f->tag, invlong()); /* for 64-bit pointers */
+ outTs(Hcurrent, f->tag);
+ journaln(0, f->tag);
+ if(f->unread)
+ load(f);
+ else{
+ if(f->_.nc>0){
+ rgrow(f->rasp, 0L, f->_.nc);
+ outTsll(Hgrow, f->tag, 0L, f->_.nc);
+ }
+ outTs(Hcheck0, f->tag);
+ moveto(f, f->dot.r);
+ }
+ break;
+
+ case Tworkfile:
+ i = inshort();
+ f = whichfile(i);
+ current(f);
+ f->dot.r.p1 = inlong();
+ f->dot.r.p2 = inlong();
+ f->tdot = f->dot.r;
+ journaln(0, i);
+ journaln(0, f->dot.r.p1);
+ journaln(0, f->dot.r.p2);
+ break;
+
+ case Ttype:
+ f = whichfile(inshort());
+ p0 = inlong();
+ journaln(0, p0);
+ journal(0, (char*)inp);
+ str = tmpcstr((char*)inp);
+ i = str->n;
+ loginsert(f, p0, str->s, str->n);
+ if(fileupdate(f, FALSE, FALSE))
+ seq++;
+ if(f==cmd && p0==f->_.nc-i && i>0 && str->s[i-1]=='\n'){
+ freetmpstr(str);
+ termlocked++;
+ termcommand();
+ }else
+ freetmpstr(str);
+ f->dot.r.p1 = f->dot.r.p2 = p0+i; /* terminal knows this already */
+ f->tdot = f->dot.r;
+ break;
+
+ case Tcut:
+ f = whichfile(inshort());
+ p0 = inlong();
+ p1 = inlong();
+ journaln(0, p0);
+ journaln(0, p1);
+ logdelete(f, p0, p1);
+ if(fileupdate(f, FALSE, FALSE))
+ seq++;
+ f->dot.r.p1 = f->dot.r.p2 = p0;
+ f->tdot = f->dot.r; /* terminal knows the value of dot already */
+ break;
+
+ case Tpaste:
+ f = whichfile(inshort());
+ p0 = inlong();
+ journaln(0, p0);
+ for(l=0; l<snarfbuf.nc; l+=m){
+ m = snarfbuf.nc-l;
+ if(m>BLOCKSIZE)
+ m = BLOCKSIZE;
+ bufread(&snarfbuf, l, genbuf, m);
+ loginsert(f, p0, tmprstr(genbuf, m)->s, m);
+ }
+ if(fileupdate(f, FALSE, TRUE))
+ seq++;
+ f->dot.r.p1 = p0;
+ f->dot.r.p2 = p0+snarfbuf.nc;
+ f->tdot.p1 = -1; /* force telldot to tell (arguably a BUG) */
+ telldot(f);
+ outTs(Hunlockfile, f->tag);
+ break;
+
+ case Tsnarf:
+ i = inshort();
+ p0 = inlong();
+ p1 = inlong();
+ snarf(whichfile(i), p0, p1, &snarfbuf, 0);
+ break;
+
+ case Tstartnewfile:
+ l = invlong();
+ Strdupl(&genstr, empty);
+ f = newfile();
+ f->rasp = emalloc(sizeof(List));
+ outTsv(Hbindname, f->tag, l);
+ logsetname(f, &genstr);
+ outTs(Hcurrent, f->tag);
+ current(f);
+ load(f);
+ break;
+
+ case Twrite:
+ termlocked++;
+ i = inshort();
+ journaln(0, i);
+ f = whichfile(i);
+ addr.r.p1 = 0;
+ addr.r.p2 = f->_.nc;
+ if(f->name.s[0] == 0)
+ error(Enoname);
+ Strduplstr(&genstr, &f->name);
+ writef(f);
+ break;
+
+ case Tclose:
+ termlocked++;
+ i = inshort();
+ journaln(0, i);
+ f = whichfile(i);
+ current(f);
+ trytoclose(f);
+ /* if trytoclose fails, will error out */
+ delete(f);
+ break;
+
+ case Tlook:
+ f = whichfile(inshort());
+ termlocked++;
+ p0 = inlong();
+ p1 = inlong();
+ journaln(0, p0);
+ journaln(0, p1);
+ setgenstr(f, p0, p1);
+ for(l = 0; l<genstr.n; l++){
+ i = genstr.s[l];
+ if(utfrune(".*+?(|)\\[]^$", i))
+ Strinsert(&genstr, tmpcstr("\\"), l++);
+ }
+ Straddc(&genstr, '\0');
+ nextmatch(f, &genstr, p1, 1);
+ moveto(f, sel.p[0]);
+ break;
+
+ case Tsearch:
+ termlocked++;
+ if(curfile == 0)
+ error(Enofile);
+ if(lastpat.s[0] == 0)
+ panic("Tsearch");
+ nextmatch(curfile, &lastpat, curfile->dot.r.p2, 1);
+ moveto(curfile, sel.p[0]);
+ break;
+
+ case Tsend:
+ termlocked++;
+ inshort(); /* ignored */
+ p0 = inlong();
+ p1 = inlong();
+ setgenstr(cmd, p0, p1);
+ bufreset(&snarfbuf);
+ bufinsert(&snarfbuf, (Posn)0, genstr.s, genstr.n);
+ outTl(Hsnarflen, genstr.n);
+ if(genstr.s[genstr.n-1] != '\n')
+ Straddc(&genstr, '\n');
+ loginsert(cmd, cmd->_.nc, genstr.s, genstr.n);
+ fileupdate(cmd, FALSE, TRUE);
+ cmd->dot.r.p1 = cmd->dot.r.p2 = cmd->_.nc;
+ telldot(cmd);
+ termcommand();
+ break;
+
+ case Tdclick:
+ f = whichfile(inshort());
+ p1 = inlong();
+ doubleclick(f, p1);
+ f->tdot.p1 = f->tdot.p2 = p1;
+ telldot(f);
+ outTs(Hunlockfile, f->tag);
+ break;
+
+ case Tstartsnarf:
+ if (snarfbuf.nc <= 0) { /* nothing to export */
+ outTs(Hsetsnarf, 0);
+ break;
+ }
+ c = 0;
+ i = 0;
+ m = snarfbuf.nc;
+ if(m > SNARFSIZE) {
+ m = SNARFSIZE;
+ dprint("?warning: snarf buffer truncated\n");
+ }
+ rp = malloc(m*sizeof(Rune));
+ if(rp){
+ bufread(&snarfbuf, 0, rp, m);
+ c = Strtoc(tmprstr(rp, m));
+ free(rp);
+ i = strlen(c);
+ }
+ outTs(Hsetsnarf, i);
+ if(c){
+ Write(1, c, i);
+ free(c);
+ } else
+ dprint("snarf buffer too long\n");
+ break;
+
+ case Tsetsnarf:
+ m = inshort();
+ if(m > SNARFSIZE)
+ error(Etoolong);
+ c = malloc(m+1);
+ if(c){
+ for(i=0; i<m; i++)
+ c[i] = rcvchar();
+ c[m] = 0;
+ str = tmpcstr(c);
+ free(c);
+ bufreset(&snarfbuf);
+ bufinsert(&snarfbuf, (Posn)0, str->s, str->n);
+ freetmpstr(str);
+ outT0(Hunlock);
+ }
+ break;
+
+ case Tack:
+ waitack = 0;
+ break;
+
+ case Tplumb:
+ f = whichfile(inshort());
+ p0 = inlong();
+ p1 = inlong();
+ pm = emalloc(sizeof(Plumbmsg));
+ pm->src = strdup("sam");
+ pm->dst = 0;
+ /* construct current directory */
+ c = Strtoc(&f->name);
+ if(c[0] == '/')
+ pm->wdir = c;
+ else{
+ wdir = emalloc(1024);
+ getwd(wdir, 1024);
+ pm->wdir = emalloc(1024);
+ snprint(pm->wdir, 1024, "%s/%s", wdir, c);
+ cleanname(pm->wdir);
+ free(wdir);
+ free(c);
+ }
+ c = strrchr(pm->wdir, '/');
+ if(c)
+ *c = '\0';
+ pm->type = strdup("text");
+ if(p1 > p0)
+ pm->attr = nil;
+ else{
+ p = p0;
+ while(p0>0 && (i=filereadc(f, p0 - 1))!=' ' && i!='\t' && i!='\n')
+ p0--;
+ while(p1<f->_.nc && (i=filereadc(f, p1))!=' ' && i!='\t' && i!='\n')
+ p1++;
+ sprint(cbuf, "click=%ld", p-p0);
+ pm->attr = plumbunpackattr(cbuf);
+ }
+ if(p0==p1 || p1-p0>=BLOCKSIZE){
+ plumbfree(pm);
+ break;
+ }
+ setgenstr(f, p0, p1);
+ pm->data = Strtoc(&genstr);
+ pm->ndata = strlen(pm->data);
+ c = plumbpack(pm, &i);
+ if(c != 0){
+ outTs(Hplumb, i);
+ Write(1, c, i);
+ free(c);
+ }
+ plumbfree(pm);
+ break;
+
+ case Texit:
+ exits(0);
+ }
+ return TRUE;
+}
+
+void
+snarf(File *f, Posn p1, Posn p2, Buffer *buf, int emptyok)
+{
+ Posn l;
+ int i;
+
+ if(!emptyok && p1==p2)
+ return;
+ bufreset(buf);
+ /* Stage through genbuf to avoid compaction problems (vestigial) */
+ if(p2 > f->_.nc){
+ fprint(2, "bad snarf addr p1=%ld p2=%ld f->_.nc=%d\n", p1, p2, f->_.nc); /*ZZZ should never happen, can remove */
+ p2 = f->_.nc;
+ }
+ for(l=p1; l<p2; l+=i){
+ i = p2-l>BLOCKSIZE? BLOCKSIZE : p2-l;
+ bufread(f, l, genbuf, i);
+ bufinsert(buf, buf->nc, tmprstr(genbuf, i)->s, i);
+ }
+}
+
+int
+inshort(void)
+{
+ ushort n;
+
+ n = inp[0] | (inp[1]<<8);
+ inp += 2;
+ return n;
+}
+
+long
+inlong(void)
+{
+ ulong n;
+
+ n = inp[0] | (inp[1]<<8) | (inp[2]<<16) | (inp[3]<<24);
+ inp += 4;
+ return n;
+}
+
+long
+invlong(void)
+{
+ ulong n;
+
+ n = (inp[7]<<24) | (inp[6]<<16) | (inp[5]<<8) | inp[4];
+ n = (n<<16) | (inp[3]<<8) | inp[2];
+ n = (n<<16) | (inp[1]<<8) | inp[0];
+ inp += 8;
+ return n;
+}
+
+void
+setgenstr(File *f, Posn p0, Posn p1)
+{
+ if(p0 != p1){
+ if(p1-p0 >= TBLOCKSIZE)
+ error(Etoolong);
+ Strinsure(&genstr, p1-p0);
+ bufread(f, p0, genbuf, p1-p0);
+ memmove(genstr.s, genbuf, RUNESIZE*(p1-p0));
+ genstr.n = p1-p0;
+ }else{
+ if(snarfbuf.nc == 0)
+ error(Eempty);
+ if(snarfbuf.nc > TBLOCKSIZE)
+ error(Etoolong);
+ bufread(&snarfbuf, (Posn)0, genbuf, snarfbuf.nc);
+ Strinsure(&genstr, snarfbuf.nc);
+ memmove(genstr.s, genbuf, RUNESIZE*snarfbuf.nc);
+ genstr.n = snarfbuf.nc;
+ }
+}
+
+void
+outT0(Hmesg type)
+{
+ outstart(type);
+ outsend();
+}
+
+void
+outTl(Hmesg type, long l)
+{
+ outstart(type);
+ outlong(l);
+ outsend();
+}
+
+void
+outTs(Hmesg type, int s)
+{
+ outstart(type);
+ journaln(1, s);
+ outshort(s);
+ outsend();
+}
+
+void
+outS(String *s)
+{
+ char *c;
+ int i;
+
+ c = Strtoc(s);
+ i = strlen(c);
+ outcopy(i, c);
+ if(i > 99)
+ c[99] = 0;
+ journaln(1, i);
+ journal(1, c);
+ free(c);
+}
+
+void
+outTsS(Hmesg type, int s1, String *s)
+{
+ outstart(type);
+ outshort(s1);
+ outS(s);
+ outsend();
+}
+
+void
+outTslS(Hmesg type, int s1, Posn l1, String *s)
+{
+ outstart(type);
+ outshort(s1);
+ journaln(1, s1);
+ outlong(l1);
+ journaln(1, l1);
+ outS(s);
+ outsend();
+}
+
+void
+outTS(Hmesg type, String *s)
+{
+ outstart(type);
+ outS(s);
+ outsend();
+}
+
+void
+outTsllS(Hmesg type, int s1, Posn l1, Posn l2, String *s)
+{
+ outstart(type);
+ outshort(s1);
+ outlong(l1);
+ outlong(l2);
+ journaln(1, l1);
+ journaln(1, l2);
+ outS(s);
+ outsend();
+}
+
+void
+outTsll(Hmesg type, int s, Posn l1, Posn l2)
+{
+ outstart(type);
+ outshort(s);
+ outlong(l1);
+ outlong(l2);
+ journaln(1, l1);
+ journaln(1, l2);
+ outsend();
+}
+
+void
+outTsl(Hmesg type, int s, Posn l)
+{
+ outstart(type);
+ outshort(s);
+ outlong(l);
+ journaln(1, l);
+ outsend();
+}
+
+void
+outTsv(Hmesg type, int s, Posn l)
+{
+ outstart(type);
+ outshort(s);
+ outvlong((void*)l);
+ journaln(1, l);
+ outsend();
+}
+
+void
+outstart(Hmesg type)
+{
+ journal(1, hname[type]);
+ outmsg[0] = type;
+ outp = outmsg+3;
+}
+
+void
+outcopy(int count, void *data)
+{
+ memmove(outp, data, count);
+ outp += count;
+}
+
+void
+outshort(int s)
+{
+ *outp++ = s;
+ *outp++ = s>>8;
+}
+
+void
+outlong(long l)
+{
+ *outp++ = l;
+ *outp++ = l>>8;
+ *outp++ = l>>16;
+ *outp++ = l>>24;
+}
+
+void
+outvlong(void *v)
+{
+ int i;
+ ulong l;
+
+ l = (ulong) v;
+ for(i = 0; i < 8; i++, l >>= 8)
+ *outp++ = l;
+}
+
+void
+outsend(void)
+{
+ int outcount;
+
+ outcount = outp-outmsg;
+ outcount -= 3;
+ outmsg[1] = outcount;
+ outmsg[2] = outcount>>8;
+ outmsg = outp;
+ if(!noflush){
+ outcount = outmsg-outdata;
+ if (write(1, (char*) outdata, outcount) != outcount)
+ rescue();
+ outmsg = outdata;
+ return;
+ }
+ if(outmsg < outdata+DATASIZE)
+ return;
+ outflush();
+}
+
+void
+outflush(void)
+{
+ if(outmsg == outdata)
+ return;
+ noflush = 0;
+ outT0(Hack);
+ waitack = 1;
+ do
+ if(rcv() == 0){
+ rescue();
+ exits("eof");
+ }
+ while(waitack);
+ outmsg = outdata;
+ noflush = 1;
+}