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 if(protodebug) print("rcv in\n");42 while((c=rcvchar()) != -1){43 if(protodebug) print(".");44 switch(state){45 case 0:46 h.type = c;47 state++;48 break;50 case 1:51 h.count0 = c;52 state++;53 break;55 case 2:56 h.count1 = c;57 count = h.count0|(h.count1<<8);58 i = 0;59 if(count > DATASIZE){60 if(++errs < 5){61 dumperrmsg(count, h.type, h.count0, c);62 state = 0;63 continue;64 }65 fprint(2, "type %d count %d\n", h.type, count);66 panic("count>DATASIZE");67 }68 if(count == 0)69 goto zerocount;70 state++;71 break;73 case 3:74 indata[i++] = c;75 if(i == count){76 zerocount:77 indata[i] = 0;78 inmesg(h.type, count);79 state = count = 0;80 continue;81 }82 break;83 }84 if(protodebug) print(":");85 }87 if(protodebug) print("rcv out\n");88 }90 Text *91 whichtext(int tg)92 {93 int i;95 for(i=0; i<nname; i++)96 if(tag[i] == tg)97 return text[i];98 panic("whichtext");99 return 0;100 }102 void103 inmesg(Hmesg type, int count)104 {105 Text *t;106 int i, m;107 long l;108 Flayer *lp;110 m = inshort(0);111 l = inlong(2);112 switch(type){113 case -1:114 panic("rcv error");115 default:116 fprint(2, "type %d\n", type);117 panic("rcv unknown");119 case Hversion:120 hversion = m;121 break;123 case Hbindname:124 l = invlong(2); /* for 64-bit pointers */125 if((i=whichmenu(m)) < 0)126 break;127 /* in case of a race, a bindname may already have occurred */128 if((t=whichtext(m)) == 0)129 t=(Text *)l;130 else /* let the old one win; clean up the new one */131 while(((Text *)l)->nwin>0)132 closeup(&((Text *)l)->l[((Text *)l)->front]);133 text[i] = t;134 text[i]->tag = m;135 break;137 case Hcurrent:138 if(whichmenu(m)<0)139 break;140 t = whichtext(m);141 i = which && ((Text *)which->user1)==&cmd && m!=cmd.tag;142 if(t==0 && (t = sweeptext(0, m))==0)143 break;144 if(t->l[t->front].textfn==0)145 panic("Hcurrent");146 lp = &t->l[t->front];147 if(i){148 flupfront(lp);149 flborder(lp, 0);150 work = lp;151 }else152 current(lp);153 break;155 case Hmovname:156 if((m=whichmenu(m)) < 0)157 break;158 t = text[m];159 l = tag[m];160 i = name[m][0];161 text[m] = 0; /* suppress panic in menudel */162 menudel(m);163 if(t == &cmd)164 m = 0;165 else{166 if (nname>0 && text[0]==&cmd)167 m = 1;168 else m = 0;169 for(; m<nname; m++)170 if(strcmp((char*)indata+2, (char*)name[m]+1)<0)171 break;172 }173 menuins(m, indata+2, t, i, (int)l);174 break;176 case Hgrow:177 if(whichmenu(m) >= 0)178 hgrow(m, l, inlong(6), 1);179 break;181 case Hnewname:182 menuins(0, (uchar *)"", (Text *)0, ' ', m);183 break;185 case Hcheck0:186 i = whichmenu(m);187 if(i>=0) {188 t = text[i];189 if(t)190 t->lock++;191 outTs(Tcheck, m);192 }193 break;195 case Hcheck:196 i = whichmenu(m);197 if(i>=0) {198 t = text[i];199 if(t && t->lock)200 t->lock--;201 hcheck(m);202 }203 break;205 case Hunlock:206 clrlock();207 break;209 case Hdata:210 if(whichmenu(m) >= 0)211 l += hdata(m, l, indata+6, count-6);212 Checkscroll:213 if(m == cmd.tag){214 for(i=0; i<NL; i++){215 lp = &cmd.l[i];216 if(lp->textfn)217 center(lp, l>=0? l : lp->p1);218 }219 }220 break;222 case Horigin:223 if(whichmenu(m) >= 0)224 horigin(m, l);225 break;227 case Hunlockfile:228 if(whichmenu(m)>=0 && (t = whichtext(m))->lock){229 --t->lock;230 l = -1;231 goto Checkscroll;232 }233 break;235 case Hsetdot:236 if(whichmenu(m) >= 0)237 hsetdot(m, l, inlong(6));238 break;240 case Hgrowdata:241 if(whichmenu(m)<0)242 break;243 hgrow(m, l, inlong(6), 0);244 whichtext(m)->lock++; /* fake the request */245 l += hdata(m, l, indata+10, count-10);246 goto Checkscroll;248 case Hmoveto:249 if(whichmenu(m)>=0)250 hmoveto(m, l);251 break;253 case Hclean:254 if((m = whichmenu(m)) >= 0)255 name[m][0] = ' ';256 break;258 case Hdirty:259 if((m = whichmenu(m))>=0)260 name[m][0] = '\'';261 break;263 case Hdelname:264 if((m=whichmenu(m)) >= 0)265 menudel(m);266 break;268 case Hcut:269 if(whichmenu(m) >= 0)270 hcut(m, l, inlong(6));271 break;273 case Hclose:274 if(whichmenu(m)<0 || (t = whichtext(m))==0)275 break;276 l = t->nwin;277 for(i = 0,lp = t->l; l>0 && i<NL; i++,lp++)278 if(lp->textfn){279 closeup(lp);280 --l;281 }282 break;284 case Hsetpat:285 setpat((char *)indata);286 break;288 case Hsetsnarf:289 hsetsnarf(m);290 break;292 case Hsnarflen:293 snarflen = inlong(0);294 break;296 case Hack:297 outT0(Tack);298 break;300 case Hexit:301 outT0(Texit);302 threadexitsall(nil);303 break;305 case Hplumb:306 hplumb(m);307 break;308 }309 }311 void312 setlock(void)313 {314 hostlock++;315 setcursor(mousectl, cursor = &lockarrow);316 }318 void319 clrlock(void)320 {321 hasunlocked = 1;322 if(hostlock > 0)323 hostlock--;324 if(hostlock == 0)325 setcursor(mousectl, cursor=(Cursor *)0);326 }328 void329 startfile(Text *t)330 {331 outTsv(Tstartfile, t->tag, t); /* for 64-bit pointers */332 setlock();333 }335 void336 startnewfile(int type, Text *t)337 {338 t->tag = Untagged;339 outTv(type, t); /* for 64-bit pointers */340 }342 int343 inshort(int n)344 {345 return indata[n]|(indata[n+1]<<8);346 }348 long349 inlong(int n)350 {351 return indata[n]|(indata[n+1]<<8)|352 ((long)indata[n+2]<<16)|((long)indata[n+3]<<24);353 }355 long356 invlong(int n)357 {358 long l;360 l = (indata[n+7]<<24) | (indata[n+6]<<16) | (indata[n+5]<<8) | indata[n+4];361 l = (l<<16) | (indata[n+3]<<8) | indata[n+2];362 l = (l<<16) | (indata[n+1]<<8) | indata[n];363 return l;364 }366 void367 outT0(Tmesg type)368 {369 outstart(type);370 outsend();371 }373 void374 outTl(Tmesg type, long l)375 {376 outstart(type);377 outlong(l);378 outsend();379 }381 void382 outTs(Tmesg type, int s)383 {384 outstart(type);385 outshort(s);386 outsend();387 }389 void390 outTss(Tmesg type, int s1, int s2)391 {392 outstart(type);393 outshort(s1);394 outshort(s2);395 outsend();396 }398 void399 outTsll(Tmesg type, int s1, long l1, long l2)400 {401 outstart(type);402 outshort(s1);403 outlong(l1);404 outlong(l2);405 outsend();406 }408 void409 outTsl(Tmesg type, int s1, long l1)410 {411 outstart(type);412 outshort(s1);413 outlong(l1);414 outsend();415 }417 void418 outTsv(Tmesg type, int s1, void *l1)419 {420 outstart(type);421 outshort(s1);422 outvlong(l1);423 outsend();424 }426 void427 outTv(Tmesg type, void *l1)428 {429 outstart(type);430 outvlong(l1);431 outsend();432 }434 void435 outTslS(Tmesg type, int s1, long l1, Rune *s)436 {437 char buf[DATASIZE*3+1];438 char *c;440 outstart(type);441 outshort(s1);442 outlong(l1);443 c = buf;444 while(*s)445 c += runetochar(c, s++);446 *c++ = 0;447 outcopy(c-buf, (uchar *)buf);448 outsend();449 }451 void452 outTsls(Tmesg type, int s1, long l1, int s2)453 {454 outstart(type);455 outshort(s1);456 outlong(l1);457 outshort(s2);458 outsend();459 }461 void462 outstart(Tmesg type)463 {464 outdata[0] = type;465 outcount = 0;466 }468 void469 outcopy(int count, uchar *data)470 {471 while(count--)472 outdata[HSIZE+outcount++] = *data++;473 }475 void476 outshort(int s)477 {478 uchar buf[2];480 buf[0]=s;481 buf[1]=s>>8;482 outcopy(2, buf);483 }485 void486 outlong(long l)487 {488 uchar buf[4];490 buf[0]=l;491 buf[1]=l>>8;492 buf[2]=l>>16;493 buf[3]=l>>24;494 outcopy(4, buf);495 }497 void498 outvlong(void *v)499 {500 int i;501 ulong l;502 uchar buf[8];504 l = (ulong) v;505 for(i = 0; i < sizeof(buf); i++, l >>= 8)506 buf[i] = l;508 outcopy(8, buf);509 }511 void512 outsend(void)513 {514 if(outcount>DATASIZE-HSIZE)515 panic("outcount>sizeof outdata");516 outdata[1]=outcount;517 outdata[2]=outcount>>8;518 if(write(hostfd[1], (char *)outdata, outcount+HSIZE)!=outcount+HSIZE)519 panic("write error");520 }523 void524 hsetdot(int m, long p0, long p1)525 {526 Text *t = whichtext(m);527 Flayer *l = &t->l[t->front];529 flushtyping(1);530 flsetselect(l, p0, p1);531 }533 void534 horigin(int m, long p0)535 {536 Text *t = whichtext(m);537 Flayer *l = &t->l[t->front];538 long a;539 ulong n;540 Rune *r;542 if(!flprepare(l)){543 l->origin = p0;544 return;545 }546 a = p0-l->origin;547 if(a>=0 && a<l->f.nchars)548 frdelete(&l->f, 0, a);549 else if(a<0 && -a<l->f.nchars){550 r = rload(&t->rasp, p0, l->origin, &n);551 frinsert(&l->f, r, r+n, 0);552 }else553 frdelete(&l->f, 0, l->f.nchars);554 l->origin = p0;555 scrdraw(l, t->rasp.nrunes);556 if(l->visible==Some)557 flrefresh(l, l->entire, 0);558 hcheck(m);559 }561 void562 hmoveto(int m, long p0)563 {564 Text *t = whichtext(m);565 Flayer *l = &t->l[t->front];567 if(p0<l->origin || p0-l->origin>l->f.nchars*9/10)568 outTsll(Torigin, m, p0, 2L);569 }571 void572 hcheck(int m)573 {574 Flayer *l;575 Text *t;576 int reqd = 0, i;577 long n, nl, a;578 Rune *r;580 if(m == Untagged)581 return;582 t = whichtext(m);583 if(t == 0) /* possible in a half-built window */584 return;585 for(l = &t->l[0], i = 0; i<NL; i++, l++){586 if(l->textfn==0 || !flprepare(l)) /* BUG: don't587 need this if BUG below588 is fixed */589 continue;590 a = t->l[i].origin;591 n = rcontig(&t->rasp, a, a+l->f.nchars, 1);592 if(n<l->f.nchars) /* text missing in middle of screen */593 a+=n;594 else{ /* text missing at end of screen? */595 Again:596 if(l->f.lastlinefull)597 goto Checksel; /* all's well */598 a = t->l[i].origin+l->f.nchars;599 n = t->rasp.nrunes-a;600 if(n==0)601 goto Checksel;602 if(n>TBLOCKSIZE)603 n = TBLOCKSIZE;604 n = rcontig(&t->rasp, a, a+n, 1);605 if(n>0){606 rload(&t->rasp, a, a+n, 0);607 nl = l->f.nchars;608 r = scratch;609 flinsert(l, r, r+n, l->origin+nl);610 if(nl == l->f.nchars) /* made no progress */611 goto Checksel;612 goto Again;613 }614 }615 if(!reqd){616 n = rcontig(&t->rasp, a, a+TBLOCKSIZE, 0);617 if(n <= 0)618 panic("hcheck request==0");619 outTsls(Trequest, m, a, (int)n);620 outTs(Tcheck, m);621 t->lock++; /* for the Trequest */622 t->lock++; /* for the Tcheck */623 reqd++;624 }625 Checksel:626 flsetselect(l, l->p0, l->p1);627 }628 }630 void631 flnewlyvisible(Flayer *l)632 {633 hcheck(((Text *)l->user1)->tag);634 }636 void637 hsetsnarf(int nc)638 {639 char *s2;640 char *s1;641 int i;642 int n;644 setcursor(mousectl, &deadmouse);645 s2 = alloc(nc+1);646 for(i=0; i<nc; i++)647 s2[i] = getch();648 s2[nc] = 0;649 n = snarfswap(s2, nc, &s1);650 if(n >= 0){651 if(!s1)652 n = 0;653 if(n > 65535){654 s1 = strdup("<snarf too long>");655 if (!s1)656 panic("strdup");657 n = strlen(s1);658 }else{659 s1 = realloc(s1, n+1);660 if (!s1)661 panic("realloc");662 s1[n] = 0;663 }664 snarflen = n;665 outTs(Tsetsnarf, n);666 if(n>0 && write(hostfd[1], s1, n)!=n)667 panic("snarf write error");668 free(s1);669 }else670 outTs(Tsetsnarf, 0);671 free(s2);672 setcursor(mousectl, cursor);673 }675 void676 hplumb(int nc)677 {678 int i;679 char *s;680 Plumbmsg *m;682 s = alloc(nc);683 for(i=0; i<nc; i++)684 s[i] = getch();685 if(plumbfd > 0){686 m = plumbunpack(s, nc);687 if(m != 0)688 plumbsend(plumbfd, m);689 plumbfree(m);690 }691 free(s);692 }694 void695 hgrow(int m, long a, long new, int req)696 {697 int i;698 Flayer *l;699 Text *t = whichtext(m);700 long o, b;702 if(new <= 0)703 panic("hgrow");704 rresize(&t->rasp, a, 0L, new);705 for(l = &t->l[0], i = 0; i<NL; i++, l++){706 if(l->textfn == 0)707 continue;708 o = l->origin;709 b = a-o-rmissing(&t->rasp, o, a);710 if(a < o)711 l->origin+=new;712 if(a < l->p0)713 l->p0+=new;714 if(a < l->p1)715 l->p1+=new;716 /* must prevent b temporarily becoming unsigned */717 if(!req || a<o || (b>0 && b>l->f.nchars) ||718 (l->f.nchars==0 && a-o>0))719 continue;720 if(new>TBLOCKSIZE)721 new = TBLOCKSIZE;722 outTsls(Trequest, m, a, (int)new);723 t->lock++;724 req = 0;725 }726 }728 int729 hdata1(Text *t, long a, Rune *r, int len)730 {731 int i;732 Flayer *l;733 long o, b;735 for(l = &t->l[0], i=0; i<NL; i++, l++){736 if(l->textfn==0)737 continue;738 o = l->origin;739 b = a-o-rmissing(&t->rasp, o, a);740 /* must prevent b temporarily becoming unsigned */741 if(a<o || (b>0 && b>l->f.nchars))742 continue;743 flinsert(l, r, r+len, o+b);744 }745 rdata(&t->rasp, a, a+len, r);746 rclean(&t->rasp);747 return len;748 }750 int751 hdata(int m, long a, uchar *s, int len)752 {753 int i, w;754 Text *t = whichtext(m);755 Rune buf[DATASIZE], *r;757 if(t->lock)758 --t->lock;759 if(len == 0)760 return 0;761 r = buf;762 for(i=0; i<len; i+=w,s+=w)763 w = chartorune(r++, (char*)s);764 return hdata1(t, a, buf, r-buf);765 }767 int768 hdatarune(int m, long a, Rune *r, int len)769 {770 Text *t = whichtext(m);772 if(t->lock)773 --t->lock;774 if(len == 0)775 return 0;776 return hdata1(t, a, r, len);777 }779 void780 hcut(int m, long a, long old)781 {782 Flayer *l;783 Text *t = whichtext(m);784 int i;785 long o, b;787 if(t->lock)788 --t->lock;789 for(l = &t->l[0], i = 0; i<NL; i++, l++){790 if(l->textfn == 0)791 continue;792 o = l->origin;793 b = a-o-rmissing(&t->rasp, o, a);794 /* must prevent b temporarily becoming unsigned */795 if((b<0 || b<l->f.nchars) && a+old>=o){796 fldelete(l, b<0? o : o+b,797 a+old-rmissing(&t->rasp, o, a+old));798 }799 if(a+old<o)800 l->origin-=old;801 else if(a<=o)802 l->origin = a;803 if(a+old<l->p0)804 l->p0-=old;805 else if(a<=l->p0)806 l->p0 = a;807 if(a+old<l->p1)808 l->p1-=old;809 else if(a<=l->p1)810 l->p1 = a;811 }812 rresize(&t->rasp, a, old, 0L);813 rclean(&t->rasp);814 }