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];20 int exiting;22 void inmesg(Hmesg, int);23 int inshort(int);24 long inlong(int);25 vlong invlong(int);26 void hsetdot(int, long, long);27 void hmoveto(int, long);28 void hsetsnarf(int);29 void hplumb(int);30 void clrlock(void);31 int snarfswap(char*, int, char**);34 void35 rcv(void)36 {37 int c;38 static int state = 0;39 static int count = 0;40 static int i = 0;41 static int errs = 0;43 if(protodebug) print("rcv in\n");44 while((c=rcvchar()) != -1){45 if(protodebug) print(".");46 switch(state){47 case 0:48 h.type = c;49 state++;50 break;52 case 1:53 h.count0 = c;54 state++;55 break;57 case 2:58 h.count1 = c;59 count = h.count0|(h.count1<<8);60 i = 0;61 if(count > DATASIZE){62 if(++errs < 5){63 dumperrmsg(count, h.type, h.count0, c);64 state = 0;65 continue;66 }67 fprint(2, "type %d count %d\n", h.type, count);68 panic("count>DATASIZE");69 }70 if(count == 0)71 goto zerocount;72 state++;73 break;75 case 3:76 indata[i++] = c;77 if(i == count){78 zerocount:79 indata[i] = 0;80 inmesg(h.type, count);81 state = count = 0;82 continue;83 }84 break;85 }86 if(protodebug) print(":");87 }89 if(protodebug) print("rcv out\n");90 }92 Text *93 whichtext(int tg)94 {95 int i;97 for(i=0; i<nname; i++)98 if(tag[i] == tg)99 return text[i];100 panic("whichtext");101 return 0;102 }104 void105 inmesg(Hmesg type, int count)106 {107 Text *t;108 int i, m;109 long l;110 Flayer *lp;112 m = inshort(0);113 l = inlong(2);114 switch(type){115 case -1:116 panic("rcv error");117 default:118 fprint(2, "type %d\n", type);119 panic("rcv unknown");121 case Hversion:122 hversion = m;123 break;125 case Hbindname:126 l = invlong(2); /* for 64-bit pointers */127 if((i=whichmenu(m)) < 0)128 break;129 /* in case of a race, a bindname may already have occurred */130 if((t=whichtext(m)) == 0)131 t=(Text *)l;132 else /* let the old one win; clean up the new one */133 while(((Text *)l)->nwin>0)134 closeup(&((Text *)l)->l[((Text *)l)->front]);135 text[i] = t;136 text[i]->tag = m;137 break;139 case Hcurrent:140 if(whichmenu(m)<0)141 break;142 t = whichtext(m);143 i = which && ((Text *)which->user1)==&cmd && m!=cmd.tag;144 if(t==0 && (t = sweeptext(0, m))==0)145 break;146 if(t->l[t->front].textfn==0)147 panic("Hcurrent");148 lp = &t->l[t->front];149 if(i){150 flupfront(lp);151 flborder(lp, 0);152 work = lp;153 }else154 current(lp);155 break;157 case Hmovname:158 if((m=whichmenu(m)) < 0)159 break;160 t = text[m];161 l = tag[m];162 i = name[m][0];163 text[m] = 0; /* suppress panic in menudel */164 menudel(m);165 if(t == &cmd)166 m = 0;167 else{168 if (nname>0 && text[0]==&cmd)169 m = 1;170 else m = 0;171 for(; m<nname; m++)172 if(strcmp((char*)indata+2, (char*)name[m]+1)<0)173 break;174 }175 menuins(m, indata+2, t, i, (int)l);176 break;178 case Hgrow:179 if(whichmenu(m) >= 0)180 hgrow(m, l, inlong(6), 1);181 break;183 case Hnewname:184 menuins(0, (uchar *)"", (Text *)0, ' ', m);185 break;187 case Hcheck0:188 i = whichmenu(m);189 if(i>=0) {190 t = text[i];191 if(t)192 t->lock++;193 outTs(Tcheck, m);194 }195 break;197 case Hcheck:198 i = whichmenu(m);199 if(i>=0) {200 t = text[i];201 if(t && t->lock)202 t->lock--;203 hcheck(m);204 }205 break;207 case Hunlock:208 clrlock();209 break;211 case Hdata:212 if(whichmenu(m) >= 0)213 l += hdata(m, l, indata+6, count-6);214 Checkscroll:215 if(m == cmd.tag){216 for(i=0; i<NL; i++){217 lp = &cmd.l[i];218 if(lp->textfn)219 center(lp, l>=0? l : lp->p1);220 }221 }222 break;224 case Horigin:225 if(whichmenu(m) >= 0)226 horigin(m, l);227 break;229 case Hunlockfile:230 if(whichmenu(m)>=0 && (t = whichtext(m))->lock){231 --t->lock;232 l = -1;233 goto Checkscroll;234 }235 break;237 case Hsetdot:238 if(whichmenu(m) >= 0)239 hsetdot(m, l, inlong(6));240 break;242 case Hgrowdata:243 if(whichmenu(m)<0)244 break;245 hgrow(m, l, inlong(6), 0);246 whichtext(m)->lock++; /* fake the request */247 l += hdata(m, l, indata+10, count-10);248 goto Checkscroll;250 case Hmoveto:251 if(whichmenu(m)>=0)252 hmoveto(m, l);253 break;255 case Hclean:256 if((m = whichmenu(m)) >= 0)257 name[m][0] = ' ';258 break;260 case Hdirty:261 if((m = whichmenu(m))>=0)262 name[m][0] = '\'';263 break;265 case Hdelname:266 if((m=whichmenu(m)) >= 0)267 menudel(m);268 break;270 case Hcut:271 if(whichmenu(m) >= 0)272 hcut(m, l, inlong(6));273 break;275 case Hclose:276 if(whichmenu(m)<0 || (t = whichtext(m))==0)277 break;278 l = t->nwin;279 for(i = 0,lp = t->l; l>0 && i<NL; i++,lp++)280 if(lp->textfn){281 closeup(lp);282 --l;283 }284 break;286 case Hsetpat:287 setpat((char *)indata);288 break;290 case Hsetsnarf:291 hsetsnarf(m);292 break;294 case Hsnarflen:295 snarflen = inlong(0);296 break;298 case Hack:299 outT0(Tack);300 break;302 case Hexit:303 exiting = 1;304 outT0(Texit);305 threadexitsall(nil);306 break;308 case Hplumb:309 hplumb(m);310 break;311 }312 }314 void315 setlock(void)316 {317 hostlock++;318 setcursor(mousectl, cursor = &lockarrow);319 }321 void322 clrlock(void)323 {324 hasunlocked = 1;325 if(hostlock > 0)326 hostlock--;327 if(hostlock == 0)328 setcursor(mousectl, cursor=(Cursor *)0);329 }331 void332 startfile(Text *t)333 {334 outTsv(Tstartfile, t->tag, (vlong)(uintptr)t); /* for 64-bit pointers */335 setlock();336 }338 void339 startnewfile(int type, Text *t)340 {341 t->tag = Untagged;342 outTv(type, (vlong)(uintptr)t); /* for 64-bit pointers */343 }345 int346 inshort(int n)347 {348 return indata[n]|(indata[n+1]<<8);349 }351 long352 inlong(int n)353 {354 return indata[n]|(indata[n+1]<<8)|355 ((long)indata[n+2]<<16)|((long)indata[n+3]<<24);356 }358 vlong359 invlong(int n)360 {361 vlong v;363 v = (indata[n+7]<<24) | (indata[n+6]<<16) | (indata[n+5]<<8) | indata[n+4];364 v = (v<<16) | (indata[n+3]<<8) | indata[n+2];365 v = (v<<16) | (indata[n+1]<<8) | indata[n];366 return v;367 }369 void370 outT0(Tmesg type)371 {372 outstart(type);373 outsend();374 }376 void377 outTl(Tmesg type, long l)378 {379 outstart(type);380 outlong(l);381 outsend();382 }384 void385 outTs(Tmesg type, int s)386 {387 outstart(type);388 outshort(s);389 outsend();390 }392 void393 outTss(Tmesg type, int s1, int s2)394 {395 outstart(type);396 outshort(s1);397 outshort(s2);398 outsend();399 }401 void402 outTsll(Tmesg type, int s1, long l1, long l2)403 {404 outstart(type);405 outshort(s1);406 outlong(l1);407 outlong(l2);408 outsend();409 }411 void412 outTsl(Tmesg type, int s1, long l1)413 {414 outstart(type);415 outshort(s1);416 outlong(l1);417 outsend();418 }420 void421 outTsv(Tmesg type, int s1, vlong v1)422 {423 outstart(type);424 outshort(s1);425 outvlong(v1);426 outsend();427 }429 void430 outTv(Tmesg type, vlong v1)431 {432 outstart(type);433 outvlong(v1);434 outsend();435 }437 void438 outTslS(Tmesg type, int s1, long l1, Rune *s)439 {440 char buf[DATASIZE*3+1];441 char *c;443 outstart(type);444 outshort(s1);445 outlong(l1);446 c = buf;447 while(*s)448 c += runetochar(c, s++);449 *c++ = 0;450 outcopy(c-buf, (uchar *)buf);451 outsend();452 }454 void455 outTsls(Tmesg type, int s1, long l1, int s2)456 {457 outstart(type);458 outshort(s1);459 outlong(l1);460 outshort(s2);461 outsend();462 }464 void465 outstart(Tmesg type)466 {467 outdata[0] = type;468 outcount = 0;469 }471 void472 outcopy(int count, uchar *data)473 {474 while(count--)475 outdata[HSIZE+outcount++] = *data++;476 }478 void479 outshort(int s)480 {481 uchar buf[2];483 buf[0]=s;484 buf[1]=s>>8;485 outcopy(2, buf);486 }488 void489 outlong(long l)490 {491 uchar buf[4];493 buf[0]=l;494 buf[1]=l>>8;495 buf[2]=l>>16;496 buf[3]=l>>24;497 outcopy(4, buf);498 }500 void501 outvlong(vlong v)502 {503 int i;504 uchar buf[8];506 for(i = 0; i < sizeof(buf); i++){507 buf[i] = v;508 v >>= 8;509 }511 outcopy(8, buf);512 }514 void515 outsend(void)516 {517 if(outcount>DATASIZE-HSIZE)518 panic("outcount>sizeof outdata");519 outdata[1]=outcount;520 outdata[2]=outcount>>8;521 if(write(hostfd[1], (char *)outdata, outcount+HSIZE)!=outcount+HSIZE)522 panic("write error");523 }526 void527 hsetdot(int m, long p0, long p1)528 {529 Text *t = whichtext(m);530 Flayer *l = &t->l[t->front];532 flushtyping(1);533 flsetselect(l, p0, p1);534 }536 void537 horigin(int m, long p0)538 {539 Text *t = whichtext(m);540 Flayer *l = &t->l[t->front];541 long a;542 ulong n;543 Rune *r;545 if(!flprepare(l)){546 l->origin = p0;547 return;548 }549 a = p0-l->origin;550 if(a>=0 && a<l->f.nchars)551 frdelete(&l->f, 0, a);552 else if(a<0 && -a<l->f.nchars){553 r = rload(&t->rasp, p0, l->origin, &n);554 frinsert(&l->f, r, r+n, 0);555 }else556 frdelete(&l->f, 0, l->f.nchars);557 l->origin = p0;558 scrdraw(l, t->rasp.nrunes);559 if(l->visible==Some)560 flrefresh(l, l->entire, 0);561 hcheck(m);562 }564 void565 hmoveto(int m, long p0)566 {567 Text *t = whichtext(m);568 Flayer *l = &t->l[t->front];570 if(p0<l->origin || p0-l->origin>l->f.nchars*9/10)571 outTsll(Torigin, m, p0, 2L);572 }574 void575 hcheck(int m)576 {577 Flayer *l;578 Text *t;579 int reqd = 0, i;580 long n, nl, a;581 Rune *r;583 if(m == Untagged)584 return;585 t = whichtext(m);586 if(t == 0) /* possible in a half-built window */587 return;588 for(l = &t->l[0], i = 0; i<NL; i++, l++){589 if(l->textfn==0 || !flprepare(l)) /* BUG: don't590 need this if BUG below591 is fixed */592 continue;593 a = t->l[i].origin;594 n = rcontig(&t->rasp, a, a+l->f.nchars, 1);595 if(n<l->f.nchars) /* text missing in middle of screen */596 a+=n;597 else{ /* text missing at end of screen? */598 Again:599 if(l->f.lastlinefull)600 goto Checksel; /* all's well */601 a = t->l[i].origin+l->f.nchars;602 n = t->rasp.nrunes-a;603 if(n==0)604 goto Checksel;605 if(n>TBLOCKSIZE)606 n = TBLOCKSIZE;607 n = rcontig(&t->rasp, a, a+n, 1);608 if(n>0){609 rload(&t->rasp, a, a+n, 0);610 nl = l->f.nchars;611 r = scratch;612 flinsert(l, r, r+n, l->origin+nl);613 if(nl == l->f.nchars) /* made no progress */614 goto Checksel;615 goto Again;616 }617 }618 if(!reqd){619 n = rcontig(&t->rasp, a, a+TBLOCKSIZE, 0);620 if(n <= 0)621 panic("hcheck request==0");622 outTsls(Trequest, m, a, (int)n);623 outTs(Tcheck, m);624 t->lock++; /* for the Trequest */625 t->lock++; /* for the Tcheck */626 reqd++;627 }628 Checksel:629 flsetselect(l, l->p0, l->p1);630 }631 }633 void634 flnewlyvisible(Flayer *l)635 {636 hcheck(((Text *)l->user1)->tag);637 }639 void640 hsetsnarf(int nc)641 {642 char *s2;643 char *s1;644 int i;645 int n;647 setcursor(mousectl, &deadmouse);648 s2 = alloc(nc+1);649 for(i=0; i<nc; i++)650 s2[i] = getch();651 s2[nc] = 0;652 n = snarfswap(s2, nc, &s1);653 if(n >= 0){654 if(!s1)655 n = 0;656 if(n > 65535){657 s1 = strdup("<snarf too long>");658 if (!s1)659 panic("strdup");660 n = strlen(s1);661 }else{662 s1 = realloc(s1, n+1);663 if (!s1)664 panic("realloc");665 s1[n] = 0;666 }667 snarflen = n;668 outTs(Tsetsnarf, n);669 if(n>0 && write(hostfd[1], s1, n)!=n)670 panic("snarf write error");671 free(s1);672 }else673 outTs(Tsetsnarf, 0);674 free(s2);675 setcursor(mousectl, cursor);676 }678 void679 hplumb(int nc)680 {681 int i;682 char *s;683 Plumbmsg *m;685 s = alloc(nc);686 for(i=0; i<nc; i++)687 s[i] = getch();688 if(plumbfd > 0){689 m = plumbunpack(s, nc);690 if(m != 0)691 plumbsend(plumbfd, m);692 plumbfree(m);693 }694 free(s);695 }697 void698 hgrow(int m, long a, long new, int req)699 {700 int i;701 Flayer *l;702 Text *t = whichtext(m);703 long o, b;705 if(new <= 0)706 panic("hgrow");707 rresize(&t->rasp, a, 0L, new);708 for(l = &t->l[0], i = 0; i<NL; i++, l++){709 if(l->textfn == 0)710 continue;711 o = l->origin;712 b = a-o-rmissing(&t->rasp, o, a);713 if(a < o)714 l->origin+=new;715 if(a < l->p0)716 l->p0+=new;717 if(a < l->p1)718 l->p1+=new;719 /* must prevent b temporarily becoming unsigned */720 if(!req || a<o || (b>0 && b>l->f.nchars) ||721 (l->f.nchars==0 && a-o>0))722 continue;723 if(new>TBLOCKSIZE)724 new = TBLOCKSIZE;725 outTsls(Trequest, m, a, (int)new);726 t->lock++;727 req = 0;728 }729 }731 int732 hdata1(Text *t, long a, Rune *r, int len)733 {734 int i;735 Flayer *l;736 long o, b;738 for(l = &t->l[0], i=0; i<NL; i++, l++){739 if(l->textfn==0)740 continue;741 o = l->origin;742 b = a-o-rmissing(&t->rasp, o, a);743 /* must prevent b temporarily becoming unsigned */744 if(a<o || (b>0 && b>l->f.nchars))745 continue;746 flinsert(l, r, r+len, o+b);747 }748 rdata(&t->rasp, a, a+len, r);749 rclean(&t->rasp);750 return len;751 }753 int754 hdata(int m, long a, uchar *s, int len)755 {756 int i, w;757 Text *t = whichtext(m);758 Rune buf[DATASIZE], *r;760 if(t->lock)761 --t->lock;762 if(len == 0)763 return 0;764 r = buf;765 for(i=0; i<len; i+=w,s+=w)766 w = chartorune(r++, (char*)s);767 return hdata1(t, a, buf, r-buf);768 }770 int771 hdatarune(int m, long a, Rune *r, int len)772 {773 Text *t = whichtext(m);775 if(t->lock)776 --t->lock;777 if(len == 0)778 return 0;779 return hdata1(t, a, r, len);780 }782 void783 hcut(int m, long a, long old)784 {785 Flayer *l;786 Text *t = whichtext(m);787 int i;788 long o, b;790 if(t->lock)791 --t->lock;792 for(l = &t->l[0], i = 0; i<NL; i++, l++){793 if(l->textfn == 0)794 continue;795 o = l->origin;796 b = a-o-rmissing(&t->rasp, o, a);797 /* must prevent b temporarily becoming unsigned */798 if((b<0 || b<l->f.nchars) && a+old>=o){799 fldelete(l, b<0? o : o+b,800 a+old-rmissing(&t->rasp, o, a+old));801 }802 if(a+old<o)803 l->origin-=old;804 else if(a<=o)805 l->origin = a;806 if(a+old<l->p0)807 l->p0-=old;808 else if(a<=l->p0)809 l->p0 = a;810 if(a+old<l->p1)811 l->p1-=old;812 else if(a<=l->p1)813 l->p1 = a;814 }815 rresize(&t->rasp, a, old, 0L);816 rclean(&t->rasp);817 }