| #include <u.h> |
| #include <libc.h> |
| #include <draw.h> |
| #include <thread.h> |
| #include <mouse.h> |
| #include <cursor.h> |
| #include <keyboard.h> |
| #include <frame.h> |
| #include <plumb.h> |
| #include "flayer.h" |
| #include "samterm.h" |
| |
| #define HSIZE 3 /* Type + short count */ |
| Header h; |
| uchar indata[DATASIZE+1]; /* room for NUL */ |
| uchar outdata[DATASIZE]; |
| short outcount; |
| int hversion; |
| int hostfd[2]; |
| int exiting; |
| |
| void inmesg(Hmesg, int); |
| int inshort(int); |
| long inlong(int); |
| vlong invlong(int); |
| void hsetdot(int, long, long); |
| void hmoveto(int, long); |
| void hsetsnarf(int); |
| void hplumb(int); |
| void clrlock(void); |
| int snarfswap(char*, int, char**); |
| |
| |
| void |
| rcv(void) |
| { |
| int c; |
| static int state = 0; |
| static int count = 0; |
| static int i = 0; |
| static int errs = 0; |
| |
| if(protodebug) print("rcv in\n"); |
| while((c=rcvchar()) != -1){ |
| if(protodebug) print("."); |
| 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){ |
| if(++errs < 5){ |
| dumperrmsg(count, h.type, h.count0, c); |
| state = 0; |
| continue; |
| } |
| fprint(2, "type %d count %d\n", h.type, count); |
| panic("count>DATASIZE"); |
| } |
| if(count == 0) |
| goto zerocount; |
| state++; |
| break; |
| |
| case 3: |
| indata[i++] = c; |
| if(i == count){ |
| zerocount: |
| indata[i] = 0; |
| inmesg(h.type, count); |
| state = count = 0; |
| continue; |
| } |
| break; |
| } |
| if(protodebug) print(":"); |
| } |
| |
| if(protodebug) print("rcv out\n"); |
| } |
| |
| Text * |
| whichtext(int tg) |
| { |
| int i; |
| |
| for(i=0; i<nname; i++) |
| if(tag[i] == tg) |
| return text[i]; |
| panic("whichtext"); |
| return 0; |
| } |
| |
| void |
| inmesg(Hmesg type, int count) |
| { |
| Text *t; |
| int i, m; |
| long l; |
| Flayer *lp; |
| |
| m = inshort(0); |
| l = inlong(2); |
| switch(type){ |
| case -1: |
| panic("rcv error"); |
| default: |
| fprint(2, "type %d\n", type); |
| panic("rcv unknown"); |
| |
| case Hversion: |
| hversion = m; |
| break; |
| |
| case Hbindname: |
| l = invlong(2); /* for 64-bit pointers */ |
| if((i=whichmenu(m)) < 0) |
| break; |
| /* in case of a race, a bindname may already have occurred */ |
| if((t=whichtext(m)) == 0) |
| t=(Text *)l; |
| else /* let the old one win; clean up the new one */ |
| while(((Text *)l)->nwin>0) |
| closeup(&((Text *)l)->l[((Text *)l)->front]); |
| text[i] = t; |
| text[i]->tag = m; |
| break; |
| |
| case Hcurrent: |
| if(whichmenu(m)<0) |
| break; |
| t = whichtext(m); |
| i = which && ((Text *)which->user1)==&cmd && m!=cmd.tag; |
| if(t==0 && (t = sweeptext(0, m))==0) |
| break; |
| if(t->l[t->front].textfn==0) |
| panic("Hcurrent"); |
| lp = &t->l[t->front]; |
| if(i){ |
| flupfront(lp); |
| flborder(lp, 0); |
| work = lp; |
| }else |
| current(lp); |
| break; |
| |
| case Hmovname: |
| if((m=whichmenu(m)) < 0) |
| break; |
| t = text[m]; |
| l = tag[m]; |
| i = name[m][0]; |
| text[m] = 0; /* suppress panic in menudel */ |
| menudel(m); |
| if(t == &cmd) |
| m = 0; |
| else{ |
| if (nname>0 && text[0]==&cmd) |
| m = 1; |
| else m = 0; |
| for(; m<nname; m++) |
| if(strcmp((char*)indata+2, (char*)name[m]+1)<0) |
| break; |
| } |
| menuins(m, indata+2, t, i, (int)l); |
| break; |
| |
| case Hgrow: |
| if(whichmenu(m) >= 0) |
| hgrow(m, l, inlong(6), 1); |
| break; |
| |
| case Hnewname: |
| menuins(0, (uchar *)"", (Text *)0, ' ', m); |
| break; |
| |
| case Hcheck0: |
| i = whichmenu(m); |
| if(i>=0) { |
| t = text[i]; |
| if(t) |
| t->lock++; |
| outTs(Tcheck, m); |
| } |
| break; |
| |
| case Hcheck: |
| i = whichmenu(m); |
| if(i>=0) { |
| t = text[i]; |
| if(t && t->lock) |
| t->lock--; |
| hcheck(m); |
| } |
| break; |
| |
| case Hunlock: |
| clrlock(); |
| break; |
| |
| case Hdata: |
| if(whichmenu(m) >= 0) |
| l += hdata(m, l, indata+6, count-6); |
| Checkscroll: |
| if(m == cmd.tag){ |
| for(i=0; i<NL; i++){ |
| lp = &cmd.l[i]; |
| if(lp->textfn) |
| center(lp, l>=0? l : lp->p1); |
| } |
| } |
| break; |
| |
| case Horigin: |
| if(whichmenu(m) >= 0) |
| horigin(m, l); |
| break; |
| |
| case Hunlockfile: |
| if(whichmenu(m)>=0 && (t = whichtext(m))->lock){ |
| --t->lock; |
| l = -1; |
| goto Checkscroll; |
| } |
| break; |
| |
| case Hsetdot: |
| if(whichmenu(m) >= 0) |
| hsetdot(m, l, inlong(6)); |
| break; |
| |
| case Hgrowdata: |
| if(whichmenu(m)<0) |
| break; |
| hgrow(m, l, inlong(6), 0); |
| whichtext(m)->lock++; /* fake the request */ |
| l += hdata(m, l, indata+10, count-10); |
| goto Checkscroll; |
| |
| case Hmoveto: |
| if(whichmenu(m)>=0) |
| hmoveto(m, l); |
| break; |
| |
| case Hclean: |
| if((m = whichmenu(m)) >= 0) |
| name[m][0] = ' '; |
| break; |
| |
| case Hdirty: |
| if((m = whichmenu(m))>=0) |
| name[m][0] = '\''; |
| break; |
| |
| case Hdelname: |
| if((m=whichmenu(m)) >= 0) |
| menudel(m); |
| break; |
| |
| case Hcut: |
| if(whichmenu(m) >= 0) |
| hcut(m, l, inlong(6)); |
| break; |
| |
| case Hclose: |
| if(whichmenu(m)<0 || (t = whichtext(m))==0) |
| break; |
| l = t->nwin; |
| for(i = 0,lp = t->l; l>0 && i<NL; i++,lp++) |
| if(lp->textfn){ |
| closeup(lp); |
| --l; |
| } |
| break; |
| |
| case Hsetpat: |
| setpat((char *)indata); |
| break; |
| |
| case Hsetsnarf: |
| hsetsnarf(m); |
| break; |
| |
| case Hsnarflen: |
| snarflen = inlong(0); |
| break; |
| |
| case Hack: |
| outT0(Tack); |
| break; |
| |
| case Hexit: |
| exiting = 1; |
| outT0(Texit); |
| threadexitsall(nil); |
| break; |
| |
| case Hplumb: |
| hplumb(m); |
| break; |
| } |
| } |
| |
| void |
| setlock(void) |
| { |
| hostlock++; |
| setcursor(mousectl, cursor = &lockarrow); |
| } |
| |
| void |
| clrlock(void) |
| { |
| hasunlocked = 1; |
| if(hostlock > 0) |
| hostlock--; |
| if(hostlock == 0) |
| setcursor(mousectl, cursor=(Cursor *)0); |
| } |
| |
| void |
| startfile(Text *t) |
| { |
| outTsv(Tstartfile, t->tag, (vlong)(uintptr)t); /* for 64-bit pointers */ |
| setlock(); |
| } |
| |
| void |
| startnewfile(int type, Text *t) |
| { |
| t->tag = Untagged; |
| outTv(type, (vlong)(uintptr)t); /* for 64-bit pointers */ |
| } |
| |
| int |
| inshort(int n) |
| { |
| return indata[n]|(indata[n+1]<<8); |
| } |
| |
| long |
| inlong(int n) |
| { |
| return indata[n]|(indata[n+1]<<8)| |
| ((long)indata[n+2]<<16)|((long)indata[n+3]<<24); |
| } |
| |
| vlong |
| invlong(int n) |
| { |
| vlong v; |
| |
| v = (indata[n+7]<<24) | (indata[n+6]<<16) | (indata[n+5]<<8) | indata[n+4]; |
| v = (v<<16) | (indata[n+3]<<8) | indata[n+2]; |
| v = (v<<16) | (indata[n+1]<<8) | indata[n]; |
| return v; |
| } |
| |
| void |
| outT0(Tmesg type) |
| { |
| outstart(type); |
| outsend(); |
| } |
| |
| void |
| outTl(Tmesg type, long l) |
| { |
| outstart(type); |
| outlong(l); |
| outsend(); |
| } |
| |
| void |
| outTs(Tmesg type, int s) |
| { |
| outstart(type); |
| outshort(s); |
| outsend(); |
| } |
| |
| void |
| outTss(Tmesg type, int s1, int s2) |
| { |
| outstart(type); |
| outshort(s1); |
| outshort(s2); |
| outsend(); |
| } |
| |
| void |
| outTsll(Tmesg type, int s1, long l1, long l2) |
| { |
| outstart(type); |
| outshort(s1); |
| outlong(l1); |
| outlong(l2); |
| outsend(); |
| } |
| |
| void |
| outTsl(Tmesg type, int s1, long l1) |
| { |
| outstart(type); |
| outshort(s1); |
| outlong(l1); |
| outsend(); |
| } |
| |
| void |
| outTsv(Tmesg type, int s1, vlong v1) |
| { |
| outstart(type); |
| outshort(s1); |
| outvlong(v1); |
| outsend(); |
| } |
| |
| void |
| outTv(Tmesg type, vlong v1) |
| { |
| outstart(type); |
| outvlong(v1); |
| outsend(); |
| } |
| |
| void |
| outTslS(Tmesg type, int s1, long l1, Rune *s) |
| { |
| char buf[DATASIZE*3+1]; |
| char *c; |
| |
| outstart(type); |
| outshort(s1); |
| outlong(l1); |
| c = buf; |
| while(*s) |
| c += runetochar(c, s++); |
| *c++ = 0; |
| outcopy(c-buf, (uchar *)buf); |
| outsend(); |
| } |
| |
| void |
| outTsls(Tmesg type, int s1, long l1, int s2) |
| { |
| outstart(type); |
| outshort(s1); |
| outlong(l1); |
| outshort(s2); |
| outsend(); |
| } |
| |
| void |
| outstart(Tmesg type) |
| { |
| outdata[0] = type; |
| outcount = 0; |
| } |
| |
| void |
| outcopy(int count, uchar *data) |
| { |
| while(count--) |
| outdata[HSIZE+outcount++] = *data++; |
| } |
| |
| void |
| outshort(int s) |
| { |
| uchar buf[2]; |
| |
| buf[0]=s; |
| buf[1]=s>>8; |
| outcopy(2, buf); |
| } |
| |
| void |
| outlong(long l) |
| { |
| uchar buf[4]; |
| |
| buf[0]=l; |
| buf[1]=l>>8; |
| buf[2]=l>>16; |
| buf[3]=l>>24; |
| outcopy(4, buf); |
| } |
| |
| void |
| outvlong(vlong v) |
| { |
| int i; |
| uchar buf[8]; |
| |
| for(i = 0; i < sizeof(buf); i++){ |
| buf[i] = v; |
| v >>= 8; |
| } |
| |
| outcopy(8, buf); |
| } |
| |
| void |
| outsend(void) |
| { |
| if(outcount>DATASIZE-HSIZE) |
| panic("outcount>sizeof outdata"); |
| outdata[1]=outcount; |
| outdata[2]=outcount>>8; |
| if(write(hostfd[1], (char *)outdata, outcount+HSIZE)!=outcount+HSIZE) |
| panic("write error"); |
| } |
| |
| |
| void |
| hsetdot(int m, long p0, long p1) |
| { |
| Text *t = whichtext(m); |
| Flayer *l = &t->l[t->front]; |
| |
| flushtyping(1); |
| flsetselect(l, p0, p1); |
| } |
| |
| void |
| horigin(int m, long p0) |
| { |
| Text *t = whichtext(m); |
| Flayer *l = &t->l[t->front]; |
| long a; |
| ulong n; |
| Rune *r; |
| |
| if(!flprepare(l)){ |
| l->origin = p0; |
| return; |
| } |
| a = p0-l->origin; |
| if(a>=0 && a<l->f.nchars) |
| frdelete(&l->f, 0, a); |
| else if(a<0 && -a<l->f.nchars){ |
| r = rload(&t->rasp, p0, l->origin, &n); |
| frinsert(&l->f, r, r+n, 0); |
| }else |
| frdelete(&l->f, 0, l->f.nchars); |
| l->origin = p0; |
| scrdraw(l, t->rasp.nrunes); |
| if(l->visible==Some) |
| flrefresh(l, l->entire, 0); |
| hcheck(m); |
| } |
| |
| void |
| hmoveto(int m, long p0) |
| { |
| Text *t = whichtext(m); |
| Flayer *l = &t->l[t->front]; |
| |
| if(p0<l->origin || p0-l->origin>l->f.nchars*9/10) |
| outTsll(Torigin, m, p0, 2L); |
| } |
| |
| void |
| hcheck(int m) |
| { |
| Flayer *l; |
| Text *t; |
| int reqd = 0, i; |
| long n, nl, a; |
| Rune *r; |
| |
| if(m == Untagged) |
| return; |
| t = whichtext(m); |
| if(t == 0) /* possible in a half-built window */ |
| return; |
| for(l = &t->l[0], i = 0; i<NL; i++, l++){ |
| if(l->textfn==0 || !flprepare(l)) /* BUG: don't |
| need this if BUG below |
| is fixed */ |
| continue; |
| a = t->l[i].origin; |
| n = rcontig(&t->rasp, a, a+l->f.nchars, 1); |
| if(n<l->f.nchars) /* text missing in middle of screen */ |
| a+=n; |
| else{ /* text missing at end of screen? */ |
| Again: |
| if(l->f.lastlinefull) |
| goto Checksel; /* all's well */ |
| a = t->l[i].origin+l->f.nchars; |
| n = t->rasp.nrunes-a; |
| if(n==0) |
| goto Checksel; |
| if(n>TBLOCKSIZE) |
| n = TBLOCKSIZE; |
| n = rcontig(&t->rasp, a, a+n, 1); |
| if(n>0){ |
| rload(&t->rasp, a, a+n, 0); |
| nl = l->f.nchars; |
| r = scratch; |
| flinsert(l, r, r+n, l->origin+nl); |
| if(nl == l->f.nchars) /* made no progress */ |
| goto Checksel; |
| goto Again; |
| } |
| } |
| if(!reqd){ |
| n = rcontig(&t->rasp, a, a+TBLOCKSIZE, 0); |
| if(n <= 0) |
| panic("hcheck request==0"); |
| outTsls(Trequest, m, a, (int)n); |
| outTs(Tcheck, m); |
| t->lock++; /* for the Trequest */ |
| t->lock++; /* for the Tcheck */ |
| reqd++; |
| } |
| Checksel: |
| flsetselect(l, l->p0, l->p1); |
| } |
| } |
| |
| void |
| flnewlyvisible(Flayer *l) |
| { |
| hcheck(((Text *)l->user1)->tag); |
| } |
| |
| void |
| hsetsnarf(int nc) |
| { |
| char *s2; |
| char *s1; |
| int i; |
| int n; |
| |
| setcursor(mousectl, &deadmouse); |
| s2 = alloc(nc+1); |
| for(i=0; i<nc; i++) |
| s2[i] = getch(); |
| s2[nc] = 0; |
| n = snarfswap(s2, nc, &s1); |
| if(n >= 0){ |
| if(!s1) |
| n = 0; |
| if(n > SNARFSIZE){ |
| s1 = strdup("<snarf too long>"); |
| if (!s1) |
| panic("strdup"); |
| n = strlen(s1); |
| }else{ |
| s1 = realloc(s1, n+1); |
| if (!s1) |
| panic("realloc"); |
| s1[n] = 0; |
| } |
| snarflen = n; |
| outTs(Tsetsnarf, n); |
| if(n>0 && write(hostfd[1], s1, n)!=n) |
| panic("snarf write error"); |
| free(s1); |
| }else |
| outTs(Tsetsnarf, 0); |
| free(s2); |
| setcursor(mousectl, cursor); |
| } |
| |
| void |
| hplumb(int nc) |
| { |
| int i; |
| char *s; |
| Plumbmsg *m; |
| |
| s = alloc(nc); |
| for(i=0; i<nc; i++) |
| s[i] = getch(); |
| if(plumbfd > 0){ |
| m = plumbunpack(s, nc); |
| if(m != 0) |
| plumbsend(plumbfd, m); |
| plumbfree(m); |
| } |
| free(s); |
| } |
| |
| void |
| hgrow(int m, long a, long new, int req) |
| { |
| int i; |
| Flayer *l; |
| Text *t = whichtext(m); |
| long o, b; |
| |
| if(new <= 0) |
| panic("hgrow"); |
| rresize(&t->rasp, a, 0L, new); |
| for(l = &t->l[0], i = 0; i<NL; i++, l++){ |
| if(l->textfn == 0) |
| continue; |
| o = l->origin; |
| b = a-o-rmissing(&t->rasp, o, a); |
| if(a < o) |
| l->origin+=new; |
| if(a < l->p0) |
| l->p0+=new; |
| if(a < l->p1) |
| l->p1+=new; |
| /* must prevent b temporarily becoming unsigned */ |
| if(!req || a<o || (b>0 && b>l->f.nchars) || |
| (l->f.nchars==0 && a-o>0)) |
| continue; |
| if(new>TBLOCKSIZE) |
| new = TBLOCKSIZE; |
| outTsls(Trequest, m, a, (int)new); |
| t->lock++; |
| req = 0; |
| } |
| } |
| |
| int |
| hdata1(Text *t, long a, Rune *r, int len) |
| { |
| int i; |
| Flayer *l; |
| long o, b; |
| |
| for(l = &t->l[0], i=0; i<NL; i++, l++){ |
| if(l->textfn==0) |
| continue; |
| o = l->origin; |
| b = a-o-rmissing(&t->rasp, o, a); |
| /* must prevent b temporarily becoming unsigned */ |
| if(a<o || (b>0 && b>l->f.nchars)) |
| continue; |
| flinsert(l, r, r+len, o+b); |
| } |
| rdata(&t->rasp, a, a+len, r); |
| rclean(&t->rasp); |
| return len; |
| } |
| |
| int |
| hdata(int m, long a, uchar *s, int len) |
| { |
| int i, w; |
| Text *t = whichtext(m); |
| Rune buf[DATASIZE], *r; |
| |
| if(t->lock) |
| --t->lock; |
| if(len == 0) |
| return 0; |
| r = buf; |
| for(i=0; i<len; i+=w,s+=w) |
| w = chartorune(r++, (char*)s); |
| return hdata1(t, a, buf, r-buf); |
| } |
| |
| int |
| hdatarune(int m, long a, Rune *r, int len) |
| { |
| Text *t = whichtext(m); |
| |
| if(t->lock) |
| --t->lock; |
| if(len == 0) |
| return 0; |
| return hdata1(t, a, r, len); |
| } |
| |
| void |
| hcut(int m, long a, long old) |
| { |
| Flayer *l; |
| Text *t = whichtext(m); |
| int i; |
| long o, b; |
| |
| if(t->lock) |
| --t->lock; |
| for(l = &t->l[0], i = 0; i<NL; i++, l++){ |
| if(l->textfn == 0) |
| continue; |
| o = l->origin; |
| b = a-o-rmissing(&t->rasp, o, a); |
| /* must prevent b temporarily becoming unsigned */ |
| if((b<0 || b<l->f.nchars) && a+old>=o){ |
| fldelete(l, b<0? o : o+b, |
| a+old-rmissing(&t->rasp, o, a+old)); |
| } |
| if(a+old<o) |
| l->origin-=old; |
| else if(a<=o) |
| l->origin = a; |
| if(a+old<l->p0) |
| l->p0-=old; |
| else if(a<=l->p0) |
| l->p0 = a; |
| if(a+old<l->p1) |
| l->p1-=old; |
| else if(a<=l->p1) |
| l->p1 = a; |
| } |
| rresize(&t->rasp, a, old, 0L); |
| rclean(&t->rasp); |
| } |