Blob
1 #include <u.h>2 #include <libc.h>3 #include <draw.h>4 #include <thread.h>5 #include <mouse.h>6 #include <cursor.h>7 #include <keyboard.h>8 #include <frame.h>9 #include <plumb.h>10 #include "flayer.h"11 #include "samterm.h"13 #define HSIZE 3 /* Type + short count */14 Header h;15 uchar indata[DATASIZE+1]; /* room for NUL */16 uchar outdata[DATASIZE];17 short outcount;18 int hversion;19 int hostfd[2];21 void inmesg(Hmesg, int);22 int inshort(int);23 long inlong(int);24 long invlong(int);25 void hsetdot(int, long, long);26 void hmoveto(int, long);27 void hsetsnarf(int);28 void hplumb(int);29 void clrlock(void);30 int snarfswap(char*, int, char**);32 void33 rcv(void)34 {35 int c;36 static int state = 0;37 static int count = 0;38 static int i = 0;39 static int errs = 0;41 while((c=rcvchar()) != -1)42 switch(state){43 case 0:44 h.type = c;45 state++;46 break;48 case 1:49 h.count0 = c;50 state++;51 break;53 case 2:54 h.count1 = c;55 count = h.count0|(h.count1<<8);56 i = 0;57 if(count > DATASIZE){58 if(++errs < 5){59 dumperrmsg(count, h.type, h.count0, c);60 state = 0;61 continue;62 }63 fprint(2, "type %d count %d\n", h.type, count);64 panic("count>DATASIZE");65 }66 if(count == 0)67 goto zerocount;68 state++;69 break;71 case 3:72 indata[i++] = c;73 if(i == count){74 zerocount:75 indata[i] = 0;76 inmesg(h.type, count);77 state = count = 0;78 continue;79 }80 break;81 }82 }84 Text *85 whichtext(int tg)86 {87 int i;89 for(i=0; i<nname; i++)90 if(tag[i] == tg)91 return text[i];92 panic("whichtext");93 return 0;94 }96 void97 inmesg(Hmesg type, int count)98 {99 Text *t;100 int i, m;101 long l;102 Flayer *lp;104 m = inshort(0);105 l = inlong(2);106 switch(type){107 case -1:108 panic("rcv error");109 default:110 fprint(2, "type %d\n", type);111 panic("rcv unknown");113 case Hversion:114 hversion = m;115 break;117 case Hbindname:118 l = invlong(2); /* for 64-bit pointers */119 if((i=whichmenu(m)) < 0)120 break;121 /* in case of a race, a bindname may already have occurred */122 if((t=whichtext(m)) == 0)123 t=(Text *)l;124 else /* let the old one win; clean up the new one */125 while(((Text *)l)->nwin>0)126 closeup(&((Text *)l)->l[((Text *)l)->front]);127 text[i] = t;128 text[i]->tag = m;129 break;131 case Hcurrent:132 if(whichmenu(m)<0)133 break;134 t = whichtext(m);135 i = which && ((Text *)which->user1)==&cmd && m!=cmd.tag;136 if(t==0 && (t = sweeptext(0, m))==0)137 break;138 if(t->l[t->front].textfn==0)139 panic("Hcurrent");140 lp = &t->l[t->front];141 if(i){142 flupfront(lp);143 flborder(lp, 0);144 work = lp;145 }else146 current(lp);147 break;149 case Hmovname:150 if((m=whichmenu(m)) < 0)151 break;152 t = text[m];153 l = tag[m];154 i = name[m][0];155 text[m] = 0; /* suppress panic in menudel */156 menudel(m);157 if(t == &cmd)158 m = 0;159 else{160 if (nname>0 && text[0]==&cmd)161 m = 1;162 else m = 0;163 for(; m<nname; m++)164 if(strcmp((char*)indata+2, (char*)name[m]+1)<0)165 break;166 }167 menuins(m, indata+2, t, i, (int)l);168 break;170 case Hgrow:171 if(whichmenu(m) >= 0)172 hgrow(m, l, inlong(6), 1);173 break;175 case Hnewname:176 menuins(0, (uchar *)"", (Text *)0, ' ', m);177 break;179 case Hcheck0:180 i = whichmenu(m);181 if(i>=0) {182 t = text[i];183 if(t)184 t->lock++;185 outTs(Tcheck, m);186 }187 break;189 case Hcheck:190 i = whichmenu(m);191 if(i>=0) {192 t = text[i];193 if(t && t->lock)194 t->lock--;195 hcheck(m);196 }197 break;199 case Hunlock:200 clrlock();201 break;203 case Hdata:204 if(whichmenu(m) >= 0)205 l += hdata(m, l, indata+6, count-6);206 Checkscroll:207 if(m == cmd.tag){208 for(i=0; i<NL; i++){209 lp = &cmd.l[i];210 if(lp->textfn)211 center(lp, l>=0? l : lp->p1);212 }213 }214 break;216 case Horigin:217 if(whichmenu(m) >= 0)218 horigin(m, l);219 break;221 case Hunlockfile:222 if(whichmenu(m)>=0 && (t = whichtext(m))->lock){223 --t->lock;224 l = -1;225 goto Checkscroll;226 }227 break;229 case Hsetdot:230 if(whichmenu(m) >= 0)231 hsetdot(m, l, inlong(6));232 break;234 case Hgrowdata:235 if(whichmenu(m)<0)236 break;237 hgrow(m, l, inlong(6), 0);238 whichtext(m)->lock++; /* fake the request */239 l += hdata(m, l, indata+10, count-10);240 goto Checkscroll;242 case Hmoveto:243 if(whichmenu(m)>=0)244 hmoveto(m, l);245 break;247 case Hclean:248 if((m = whichmenu(m)) >= 0)249 name[m][0] = ' ';250 break;252 case Hdirty:253 if((m = whichmenu(m))>=0)254 name[m][0] = '\'';255 break;257 case Hdelname:258 if((m=whichmenu(m)) >= 0)259 menudel(m);260 break;262 case Hcut:263 if(whichmenu(m) >= 0)264 hcut(m, l, inlong(6));265 break;267 case Hclose:268 if(whichmenu(m)<0 || (t = whichtext(m))==0)269 break;270 l = t->nwin;271 for(i = 0,lp = t->l; l>0 && i<NL; i++,lp++)272 if(lp->textfn){273 closeup(lp);274 --l;275 }276 break;278 case Hsetpat:279 setpat((char *)indata);280 break;282 case Hsetsnarf:283 hsetsnarf(m);284 break;286 case Hsnarflen:287 snarflen = inlong(0);288 break;290 case Hack:291 outT0(Tack);292 break;294 case Hexit:295 outT0(Texit);296 threadexitsall(nil);297 break;299 case Hplumb:300 hplumb(m);301 break;302 }303 }305 void306 setlock(void)307 {308 hostlock++;309 setcursor(mousectl, cursor = &lockarrow);310 }312 void313 clrlock(void)314 {315 hasunlocked = 1;316 if(hostlock > 0)317 hostlock--;318 if(hostlock == 0)319 setcursor(mousectl, cursor=(Cursor *)0);320 }322 void323 startfile(Text *t)324 {325 outTsv(Tstartfile, t->tag, t); /* for 64-bit pointers */326 setlock();327 }329 void330 startnewfile(int type, Text *t)331 {332 t->tag = Untagged;333 outTv(type, t); /* for 64-bit pointers */334 }336 int337 inshort(int n)338 {339 return indata[n]|(indata[n+1]<<8);340 }342 long343 inlong(int n)344 {345 return indata[n]|(indata[n+1]<<8)|346 ((long)indata[n+2]<<16)|((long)indata[n+3]<<24);347 }349 long350 invlong(int n)351 {352 long l;354 l = (indata[n+7]<<24) | (indata[n+6]<<16) | (indata[n+5]<<8) | indata[n+4];355 l = (l<<16) | (indata[n+3]<<8) | indata[n+2];356 l = (l<<16) | (indata[n+1]<<8) | indata[n];357 return l;358 }360 void361 outT0(Tmesg type)362 {363 outstart(type);364 outsend();365 }367 void368 outTl(Tmesg type, long l)369 {370 outstart(type);371 outlong(l);372 outsend();373 }375 void376 outTs(Tmesg type, int s)377 {378 outstart(type);379 outshort(s);380 outsend();381 }383 void384 outTss(Tmesg type, int s1, int s2)385 {386 outstart(type);387 outshort(s1);388 outshort(s2);389 outsend();390 }392 void393 outTsll(Tmesg type, int s1, long l1, long l2)394 {395 outstart(type);396 outshort(s1);397 outlong(l1);398 outlong(l2);399 outsend();400 }402 void403 outTsl(Tmesg type, int s1, long l1)404 {405 outstart(type);406 outshort(s1);407 outlong(l1);408 outsend();409 }411 void412 outTsv(Tmesg type, int s1, void *l1)413 {414 outstart(type);415 outshort(s1);416 outvlong(l1);417 outsend();418 }420 void421 outTv(Tmesg type, void *l1)422 {423 outstart(type);424 outvlong(l1);425 outsend();426 }428 void429 outTslS(Tmesg type, int s1, long l1, Rune *s)430 {431 char buf[DATASIZE*3+1];432 char *c;434 outstart(type);435 outshort(s1);436 outlong(l1);437 c = buf;438 while(*s)439 c += runetochar(c, s++);440 *c++ = 0;441 outcopy(c-buf, (uchar *)buf);442 outsend();443 }445 void446 outTsls(Tmesg type, int s1, long l1, int s2)447 {448 outstart(type);449 outshort(s1);450 outlong(l1);451 outshort(s2);452 outsend();453 }455 void456 outstart(Tmesg type)457 {458 outdata[0] = type;459 outcount = 0;460 }462 void463 outcopy(int count, uchar *data)464 {465 while(count--)466 outdata[HSIZE+outcount++] = *data++;467 }469 void470 outshort(int s)471 {472 uchar buf[2];474 buf[0]=s;475 buf[1]=s>>8;476 outcopy(2, buf);477 }479 void480 outlong(long l)481 {482 uchar buf[4];484 buf[0]=l;485 buf[1]=l>>8;486 buf[2]=l>>16;487 buf[3]=l>>24;488 outcopy(4, buf);489 }491 void492 outvlong(void *v)493 {494 int i;495 ulong l;496 uchar buf[8];498 l = (ulong) v;499 for(i = 0; i < sizeof(buf); i++, l >>= 8)500 buf[i] = l;502 outcopy(8, buf);503 }505 void506 outsend(void)507 {508 if(outcount>DATASIZE-HSIZE)509 panic("outcount>sizeof outdata");510 outdata[1]=outcount;511 outdata[2]=outcount>>8;512 if(write(hostfd[1], (char *)outdata, outcount+HSIZE)!=outcount+HSIZE)513 panic("write error");514 }517 void518 hsetdot(int m, long p0, long p1)519 {520 Text *t = whichtext(m);521 Flayer *l = &t->l[t->front];523 flushtyping(1);524 flsetselect(l, p0, p1);525 }527 void528 horigin(int m, long p0)529 {530 Text *t = whichtext(m);531 Flayer *l = &t->l[t->front];532 long a;533 ulong n;534 Rune *r;536 if(!flprepare(l)){537 l->origin = p0;538 return;539 }540 a = p0-l->origin;541 if(a>=0 && a<l->f.nchars)542 frdelete(&l->f, 0, a);543 else if(a<0 && -a<l->f.nchars){544 r = rload(&t->rasp, p0, l->origin, &n);545 frinsert(&l->f, r, r+n, 0);546 }else547 frdelete(&l->f, 0, l->f.nchars);548 l->origin = p0;549 scrdraw(l, t->rasp.nrunes);550 if(l->visible==Some)551 flrefresh(l, l->entire, 0);552 hcheck(m);553 }555 void556 hmoveto(int m, long p0)557 {558 Text *t = whichtext(m);559 Flayer *l = &t->l[t->front];561 if(p0<l->origin || p0-l->origin>l->f.nchars*9/10)562 outTsll(Torigin, m, p0, 2L);563 }565 void566 hcheck(int m)567 {568 Flayer *l;569 Text *t;570 int reqd = 0, i;571 long n, nl, a;572 Rune *r;574 if(m == Untagged)575 return;576 t = whichtext(m);577 if(t == 0) /* possible in a half-built window */578 return;579 for(l = &t->l[0], i = 0; i<NL; i++, l++){580 if(l->textfn==0 || !flprepare(l)) /* BUG: don't581 need this if BUG below582 is fixed */583 continue;584 a = t->l[i].origin;585 n = rcontig(&t->rasp, a, a+l->f.nchars, 1);586 if(n<l->f.nchars) /* text missing in middle of screen */587 a+=n;588 else{ /* text missing at end of screen? */589 Again:590 if(l->f.lastlinefull)591 goto Checksel; /* all's well */592 a = t->l[i].origin+l->f.nchars;593 n = t->rasp.nrunes-a;594 if(n==0)595 goto Checksel;596 if(n>TBLOCKSIZE)597 n = TBLOCKSIZE;598 n = rcontig(&t->rasp, a, a+n, 1);599 if(n>0){600 rload(&t->rasp, a, a+n, 0);601 nl = l->f.nchars;602 r = scratch;603 flinsert(l, r, r+n, l->origin+nl);604 if(nl == l->f.nchars) /* made no progress */605 goto Checksel;606 goto Again;607 }608 }609 if(!reqd){610 n = rcontig(&t->rasp, a, a+TBLOCKSIZE, 0);611 if(n <= 0)612 panic("hcheck request==0");613 outTsls(Trequest, m, a, (int)n);614 outTs(Tcheck, m);615 t->lock++; /* for the Trequest */616 t->lock++; /* for the Tcheck */617 reqd++;618 }619 Checksel:620 flsetselect(l, l->p0, l->p1);621 }622 }624 void625 flnewlyvisible(Flayer *l)626 {627 hcheck(((Text *)l->user1)->tag);628 }630 void631 hsetsnarf(int nc)632 {633 char *s2;634 char *s1;635 int i;636 int n;638 setcursor(mousectl, &deadmouse);639 s2 = alloc(nc+1);640 for(i=0; i<nc; i++)641 s2[i] = getch();642 s2[nc] = 0;643 n = snarfswap(s2, nc, &s1);644 if(n >= 0){645 if(!s1)646 n = 0;647 if(n > 65535){648 s1 = strdup("<snarf too long>");649 if (!s1)650 panic("strdup");651 n = strlen(s1);652 }else{653 s1 = realloc(s1, n+1);654 if (!s1)655 panic("realloc");656 s1[n] = 0;657 }658 snarflen = n;659 outTs(Tsetsnarf, n);660 if(n>0 && write(hostfd[1], s1, n)!=n)661 panic("snarf write error");662 free(s1);663 }else664 outTs(Tsetsnarf, 0);665 free(s2);666 setcursor(mousectl, cursor);667 }669 void670 hplumb(int nc)671 {672 int i;673 char *s;674 Plumbmsg *m;676 s = alloc(nc);677 for(i=0; i<nc; i++)678 s[i] = getch();679 if(plumbfd > 0){680 m = plumbunpack(s, nc);681 if(m != 0)682 plumbsend(plumbfd, m);683 plumbfree(m);684 }685 free(s);686 }688 void689 hgrow(int m, long a, long new, int req)690 {691 int i;692 Flayer *l;693 Text *t = whichtext(m);694 long o, b;696 if(new <= 0)697 panic("hgrow");698 rresize(&t->rasp, a, 0L, new);699 for(l = &t->l[0], i = 0; i<NL; i++, l++){700 if(l->textfn == 0)701 continue;702 o = l->origin;703 b = a-o-rmissing(&t->rasp, o, a);704 if(a < o)705 l->origin+=new;706 if(a < l->p0)707 l->p0+=new;708 if(a < l->p1)709 l->p1+=new;710 /* must prevent b temporarily becoming unsigned */711 if(!req || a<o || (b>0 && b>l->f.nchars) ||712 (l->f.nchars==0 && a-o>0))713 continue;714 if(new>TBLOCKSIZE)715 new = TBLOCKSIZE;716 outTsls(Trequest, m, a, (int)new);717 t->lock++;718 req = 0;719 }720 }722 int723 hdata1(Text *t, long a, Rune *r, int len)724 {725 int i;726 Flayer *l;727 long o, b;729 for(l = &t->l[0], i=0; i<NL; i++, l++){730 if(l->textfn==0)731 continue;732 o = l->origin;733 b = a-o-rmissing(&t->rasp, o, a);734 /* must prevent b temporarily becoming unsigned */735 if(a<o || (b>0 && b>l->f.nchars))736 continue;737 flinsert(l, r, r+len, o+b);738 }739 rdata(&t->rasp, a, a+len, r);740 rclean(&t->rasp);741 return len;742 }744 int745 hdata(int m, long a, uchar *s, int len)746 {747 int i, w;748 Text *t = whichtext(m);749 Rune buf[DATASIZE], *r;751 if(t->lock)752 --t->lock;753 if(len == 0)754 return 0;755 r = buf;756 for(i=0; i<len; i+=w,s+=w)757 w = chartorune(r++, (char*)s);758 return hdata1(t, a, buf, r-buf);759 }761 int762 hdatarune(int m, long a, Rune *r, int len)763 {764 Text *t = whichtext(m);766 if(t->lock)767 --t->lock;768 if(len == 0)769 return 0;770 return hdata1(t, a, r, len);771 }773 void774 hcut(int m, long a, long old)775 {776 Flayer *l;777 Text *t = whichtext(m);778 int i;779 long o, b;781 if(t->lock)782 --t->lock;783 for(l = &t->l[0], i = 0; i<NL; i++, l++){784 if(l->textfn == 0)785 continue;786 o = l->origin;787 b = a-o-rmissing(&t->rasp, o, a);788 /* must prevent b temporarily becoming unsigned */789 if((b<0 || b<l->f.nchars) && a+old>=o){790 fldelete(l, b<0? o : o+b,791 a+old-rmissing(&t->rasp, o, a+old));792 }793 if(a+old<o)794 l->origin-=old;795 else if(a<=o)796 l->origin = a;797 if(a+old<l->p0)798 l->p0-=old;799 else if(a<=l->p0)800 l->p0 = a;801 if(a+old<l->p1)802 l->p1-=old;803 else if(a<=l->p1)804 l->p1 = a;805 }806 rresize(&t->rasp, a, old, 0L);807 rclean(&t->rasp);808 }