diff options
Diffstat (limited to 'src/cmd/sam/mesg.c')
-rw-r--r-- | src/cmd/sam/mesg.c | 821 |
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; +} |