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;20 void inmesg(Hmesg, int);21 int inshort(int);22 long inlong(int);23 long invlong(int);24 void hsetdot(int, long, long);25 void hmoveto(int, long);26 void hsetsnarf(int);27 /* void hplumb(int); */28 void clrlock(void);29 int snarfswap(char*, int, char**);31 void32 rcv(void)33 {34 int c;35 static int state = 0;36 static int count = 0;37 static int i = 0;38 static int errs = 0;40 while((c=rcvchar()) != -1)41 switch(state){42 case 0:43 h.type = c;44 state++;45 break;47 case 1:48 h.count0 = c;49 state++;50 break;52 case 2:53 h.count1 = c;54 count = h.count0|(h.count1<<8);55 i = 0;56 if(count > DATASIZE){57 if(++errs < 5){58 dumperrmsg(count, h.type, h.count0, c);59 state = 0;60 continue;61 }62 fprint(2, "type %d count %d\n", h.type, count);63 panic("count>DATASIZE");64 }65 if(count == 0)66 goto zerocount;67 state++;68 break;70 case 3:71 indata[i++] = c;72 if(i == count){73 zerocount:74 indata[i] = 0;75 inmesg(h.type, count);76 state = count = 0;77 continue;78 }79 break;80 }81 }83 Text *84 whichtext(int tg)85 {86 int i;88 for(i=0; i<nname; i++)89 if(tag[i] == tg)90 return text[i];91 panic("whichtext");92 return 0;93 }95 void96 inmesg(Hmesg type, int count)97 {98 Text *t;99 int i, m;100 long l;101 Flayer *lp;103 m = inshort(0);104 l = inlong(2);105 switch(type){106 case -1:107 panic("rcv error");108 default:109 fprint(2, "type %d\n", type);110 panic("rcv unknown");112 case Hversion:113 hversion = m;114 break;116 case Hbindname:117 l = invlong(2); /* for 64-bit pointers */118 if((i=whichmenu(m)) < 0)119 break;120 /* in case of a race, a bindname may already have occurred */121 if((t=whichtext(m)) == 0)122 t=(Text *)l;123 else /* let the old one win; clean up the new one */124 while(((Text *)l)->nwin>0)125 closeup(&((Text *)l)->l[((Text *)l)->front]);126 text[i] = t;127 text[i]->tag = m;128 break;130 case Hcurrent:131 if(whichmenu(m)<0)132 break;133 t = whichtext(m);134 i = which && ((Text *)which->user1)==&cmd && m!=cmd.tag;135 if(t==0 && (t = sweeptext(0, m))==0)136 break;137 if(t->l[t->front].textfn==0)138 panic("Hcurrent");139 lp = &t->l[t->front];140 if(i){141 flupfront(lp);142 flborder(lp, 0);143 work = lp;144 }else145 current(lp);146 break;148 case Hmovname:149 if((m=whichmenu(m)) < 0)150 break;151 t = text[m];152 l = tag[m];153 i = name[m][0];154 text[m] = 0; /* suppress panic in menudel */155 menudel(m);156 if(t == &cmd)157 m = 0;158 else{159 if (nname>0 && text[0]==&cmd)160 m = 1;161 else m = 0;162 for(; m<nname; m++)163 if(strcmp((char*)indata+2, (char*)name[m]+1)<0)164 break;165 }166 menuins(m, indata+2, t, i, (int)l);167 break;169 case Hgrow:170 if(whichmenu(m) >= 0)171 hgrow(m, l, inlong(6), 1);172 break;174 case Hnewname:175 menuins(0, (uchar *)"", (Text *)0, ' ', m);176 break;178 case Hcheck0:179 i = whichmenu(m);180 if(i>=0) {181 t = text[i];182 if(t)183 t->lock++;184 outTs(Tcheck, m);185 }186 break;188 case Hcheck:189 i = whichmenu(m);190 if(i>=0) {191 t = text[i];192 if(t && t->lock)193 t->lock--;194 hcheck(m);195 }196 break;198 case Hunlock:199 clrlock();200 break;202 case Hdata:203 if(whichmenu(m) >= 0)204 l += hdata(m, l, indata+6, count-6);205 Checkscroll:206 if(m == cmd.tag){207 for(i=0; i<NL; i++){208 lp = &cmd.l[i];209 if(lp->textfn)210 center(lp, l>=0? l : lp->p1);211 }212 }213 break;215 case Horigin:216 if(whichmenu(m) >= 0)217 horigin(m, l);218 break;220 case Hunlockfile:221 if(whichmenu(m)>=0 && (t = whichtext(m))->lock){222 --t->lock;223 l = -1;224 goto Checkscroll;225 }226 break;228 case Hsetdot:229 if(whichmenu(m) >= 0)230 hsetdot(m, l, inlong(6));231 break;233 case Hgrowdata:234 if(whichmenu(m)<0)235 break;236 hgrow(m, l, inlong(6), 0);237 whichtext(m)->lock++; /* fake the request */238 l += hdata(m, l, indata+10, count-10);239 goto Checkscroll;241 case Hmoveto:242 if(whichmenu(m)>=0)243 hmoveto(m, l);244 break;246 case Hclean:247 if((m = whichmenu(m)) >= 0)248 name[m][0] = ' ';249 break;251 case Hdirty:252 if((m = whichmenu(m))>=0)253 name[m][0] = '\'';254 break;256 case Hdelname:257 if((m=whichmenu(m)) >= 0)258 menudel(m);259 break;261 case Hcut:262 if(whichmenu(m) >= 0)263 hcut(m, l, inlong(6));264 break;266 case Hclose:267 if(whichmenu(m)<0 || (t = whichtext(m))==0)268 break;269 l = t->nwin;270 for(i = 0,lp = t->l; l>0 && i<NL; i++,lp++)271 if(lp->textfn){272 closeup(lp);273 --l;274 }275 break;277 case Hsetpat:278 setpat((char *)indata);279 break;281 case Hsetsnarf:282 hsetsnarf(m);283 break;285 case Hsnarflen:286 snarflen = inlong(0);287 break;289 case Hack:290 outT0(Tack);291 break;293 case Hexit:294 outT0(Texit);295 threadexitsall(nil);296 break;298 /*299 case Hplumb:300 hplumb(m);301 break;302 */303 }304 }306 void307 setlock(void)308 {309 hostlock++;310 setcursor(mousectl, cursor = &lockarrow);311 }313 void314 clrlock(void)315 {316 hasunlocked = 1;317 if(hostlock > 0)318 hostlock--;319 if(hostlock == 0)320 setcursor(mousectl, cursor=(Cursor *)0);321 }323 void324 startfile(Text *t)325 {326 outTsv(Tstartfile, t->tag, t); /* for 64-bit pointers */327 setlock();328 }330 void331 startnewfile(int type, Text *t)332 {333 t->tag = Untagged;334 outTv(type, t); /* for 64-bit pointers */335 }337 int338 inshort(int n)339 {340 return indata[n]|(indata[n+1]<<8);341 }343 long344 inlong(int n)345 {346 return indata[n]|(indata[n+1]<<8)|347 ((long)indata[n+2]<<16)|((long)indata[n+3]<<24);348 }350 long351 invlong(int n)352 {353 long l;355 l = (indata[n+7]<<24) | (indata[n+6]<<16) | (indata[n+5]<<8) | indata[n+4];356 l = (l<<16) | (indata[n+3]<<8) | indata[n+2];357 l = (l<<16) | (indata[n+1]<<8) | indata[n];358 return l;359 }361 void362 outT0(Tmesg type)363 {364 outstart(type);365 outsend();366 }368 void369 outTl(Tmesg type, long l)370 {371 outstart(type);372 outlong(l);373 outsend();374 }376 void377 outTs(Tmesg type, int s)378 {379 outstart(type);380 outshort(s);381 outsend();382 }384 void385 outTss(Tmesg type, int s1, int s2)386 {387 outstart(type);388 outshort(s1);389 outshort(s2);390 outsend();391 }393 void394 outTsll(Tmesg type, int s1, long l1, long l2)395 {396 outstart(type);397 outshort(s1);398 outlong(l1);399 outlong(l2);400 outsend();401 }403 void404 outTsl(Tmesg type, int s1, long l1)405 {406 outstart(type);407 outshort(s1);408 outlong(l1);409 outsend();410 }412 void413 outTsv(Tmesg type, int s1, void *l1)414 {415 outstart(type);416 outshort(s1);417 outvlong(l1);418 outsend();419 }421 void422 outTv(Tmesg type, void *l1)423 {424 outstart(type);425 outvlong(l1);426 outsend();427 }429 void430 outTslS(Tmesg type, int s1, long l1, Rune *s)431 {432 char buf[DATASIZE*3+1];433 char *c;435 outstart(type);436 outshort(s1);437 outlong(l1);438 c = buf;439 while(*s)440 c += runetochar(c, s++);441 *c++ = 0;442 outcopy(c-buf, (uchar *)buf);443 outsend();444 }446 void447 outTsls(Tmesg type, int s1, long l1, int s2)448 {449 outstart(type);450 outshort(s1);451 outlong(l1);452 outshort(s2);453 outsend();454 }456 void457 outstart(Tmesg type)458 {459 outdata[0] = type;460 outcount = 0;461 }463 void464 outcopy(int count, uchar *data)465 {466 while(count--)467 outdata[HSIZE+outcount++] = *data++;468 }470 void471 outshort(int s)472 {473 uchar buf[2];475 buf[0]=s;476 buf[1]=s>>8;477 outcopy(2, buf);478 }480 void481 outlong(long l)482 {483 uchar buf[4];485 buf[0]=l;486 buf[1]=l>>8;487 buf[2]=l>>16;488 buf[3]=l>>24;489 outcopy(4, buf);490 }492 void493 outvlong(void *v)494 {495 int i;496 ulong l;497 uchar buf[8];499 l = (ulong) v;500 for(i = 0; i < sizeof(buf); i++, l >>= 8)501 buf[i] = l;503 outcopy(8, buf);504 }506 void507 outsend(void)508 {509 if(outcount>DATASIZE-HSIZE)510 panic("outcount>sizeof outdata");511 outdata[1]=outcount;512 outdata[2]=outcount>>8;513 if(write(1, (char *)outdata, outcount+HSIZE)!=outcount+HSIZE)514 panic("write error");515 }518 void519 hsetdot(int m, long p0, long p1)520 {521 Text *t = whichtext(m);522 Flayer *l = &t->l[t->front];524 flushtyping(1);525 flsetselect(l, p0, p1);526 }528 void529 horigin(int m, long p0)530 {531 Text *t = whichtext(m);532 Flayer *l = &t->l[t->front];533 long a;534 ulong n;535 Rune *r;537 if(!flprepare(l)){538 l->origin = p0;539 return;540 }541 a = p0-l->origin;542 if(a>=0 && a<l->f.nchars)543 frdelete(&l->f, 0, a);544 else if(a<0 && -a<l->f.nchars){545 r = rload(&t->rasp, p0, l->origin, &n);546 frinsert(&l->f, r, r+n, 0);547 }else548 frdelete(&l->f, 0, l->f.nchars);549 l->origin = p0;550 scrdraw(l, t->rasp.nrunes);551 if(l->visible==Some)552 flrefresh(l, l->entire, 0);553 hcheck(m);554 }556 void557 hmoveto(int m, long p0)558 {559 Text *t = whichtext(m);560 Flayer *l = &t->l[t->front];562 if(p0<l->origin || p0-l->origin>l->f.nchars*9/10)563 outTsll(Torigin, m, p0, 2L);564 }566 void567 hcheck(int m)568 {569 Flayer *l;570 Text *t;571 int reqd = 0, i;572 long n, nl, a;573 Rune *r;575 if(m == Untagged)576 return;577 t = whichtext(m);578 if(t == 0) /* possible in a half-built window */579 return;580 for(l = &t->l[0], i = 0; i<NL; i++, l++){581 if(l->textfn==0 || !flprepare(l)) /* BUG: don't582 need this if BUG below583 is fixed */584 continue;585 a = t->l[i].origin;586 n = rcontig(&t->rasp, a, a+l->f.nchars, 1);587 if(n<l->f.nchars) /* text missing in middle of screen */588 a+=n;589 else{ /* text missing at end of screen? */590 Again:591 if(l->f.lastlinefull)592 goto Checksel; /* all's well */593 a = t->l[i].origin+l->f.nchars;594 n = t->rasp.nrunes-a;595 if(n==0)596 goto Checksel;597 if(n>TBLOCKSIZE)598 n = TBLOCKSIZE;599 n = rcontig(&t->rasp, a, a+n, 1);600 if(n>0){601 rload(&t->rasp, a, a+n, 0);602 nl = l->f.nchars;603 r = scratch;604 flinsert(l, r, r+n, l->origin+nl);605 if(nl == l->f.nchars) /* made no progress */606 goto Checksel;607 goto Again;608 }609 }610 if(!reqd){611 n = rcontig(&t->rasp, a, a+TBLOCKSIZE, 0);612 if(n <= 0)613 panic("hcheck request==0");614 outTsls(Trequest, m, a, (int)n);615 outTs(Tcheck, m);616 t->lock++; /* for the Trequest */617 t->lock++; /* for the Tcheck */618 reqd++;619 }620 Checksel:621 flsetselect(l, l->p0, l->p1);622 }623 }625 void626 flnewlyvisible(Flayer *l)627 {628 hcheck(((Text *)l->user1)->tag);629 }631 void632 hsetsnarf(int nc)633 {634 char *s2;635 char *s1;636 int i;637 int n;639 setcursor(mousectl, &deadmouse);640 s2 = alloc(nc+1);641 for(i=0; i<nc; i++)642 s2[i] = getch();643 s2[nc] = 0;644 n = snarfswap(s2, nc, &s1);645 if(n >= 0){646 if(!s1)647 n = 0;648 s1 = realloc(s1, n+1);649 if (!s1)650 panic("realloc");651 s1[n] = 0;652 snarflen = n;653 outTs(Tsetsnarf, n);654 if(n>0 && write(1, s1, n)!=n)655 panic("snarf write error");656 free(s1);657 }else658 outTs(Tsetsnarf, 0);659 free(s2);660 setcursor(mousectl, cursor);661 }663 /*664 void665 hplumb(int nc)666 {667 int i;668 char *s;669 Plumbmsg *m;671 s = alloc(nc);672 for(i=0; i<nc; i++)673 s[i] = getch();674 if(plumbfd > 0){675 m = plumbunpack(s, nc);676 if(m != 0)677 plumbsend(plumbfd, m);678 plumbfree(m);679 }680 free(s);681 }682 */684 void685 hgrow(int m, long a, long new, int req)686 {687 int i;688 Flayer *l;689 Text *t = whichtext(m);690 long o, b;692 if(new <= 0)693 panic("hgrow");694 rresize(&t->rasp, a, 0L, new);695 for(l = &t->l[0], i = 0; i<NL; i++, l++){696 if(l->textfn == 0)697 continue;698 o = l->origin;699 b = a-o-rmissing(&t->rasp, o, a);700 if(a < o)701 l->origin+=new;702 if(a < l->p0)703 l->p0+=new;704 if(a < l->p1)705 l->p1+=new;706 /* must prevent b temporarily becoming unsigned */707 if(!req || a<o || (b>0 && b>l->f.nchars) ||708 (l->f.nchars==0 && a-o>0))709 continue;710 if(new>TBLOCKSIZE)711 new = TBLOCKSIZE;712 outTsls(Trequest, m, a, (int)new);713 t->lock++;714 req = 0;715 }716 }718 int719 hdata1(Text *t, long a, Rune *r, int len)720 {721 int i;722 Flayer *l;723 long o, b;725 for(l = &t->l[0], i=0; i<NL; i++, l++){726 if(l->textfn==0)727 continue;728 o = l->origin;729 b = a-o-rmissing(&t->rasp, o, a);730 /* must prevent b temporarily becoming unsigned */731 if(a<o || (b>0 && b>l->f.nchars))732 continue;733 flinsert(l, r, r+len, o+b);734 }735 rdata(&t->rasp, a, a+len, r);736 rclean(&t->rasp);737 return len;738 }740 int741 hdata(int m, long a, uchar *s, int len)742 {743 int i, w;744 Text *t = whichtext(m);745 Rune buf[DATASIZE], *r;747 if(t->lock)748 --t->lock;749 if(len == 0)750 return 0;751 r = buf;752 for(i=0; i<len; i+=w,s+=w)753 w = chartorune(r++, (char*)s);754 return hdata1(t, a, buf, r-buf);755 }757 int758 hdatarune(int m, long a, Rune *r, int len)759 {760 Text *t = whichtext(m);762 if(t->lock)763 --t->lock;764 if(len == 0)765 return 0;766 return hdata1(t, a, r, len);767 }769 void770 hcut(int m, long a, long old)771 {772 Flayer *l;773 Text *t = whichtext(m);774 int i;775 long o, b;777 if(t->lock)778 --t->lock;779 for(l = &t->l[0], i = 0; i<NL; i++, l++){780 if(l->textfn == 0)781 continue;782 o = l->origin;783 b = a-o-rmissing(&t->rasp, o, a);784 /* must prevent b temporarily becoming unsigned */785 if((b<0 || b<l->f.nchars) && a+old>=o){786 fldelete(l, b<0? o : o+b,787 a+old-rmissing(&t->rasp, o, a+old));788 }789 if(a+old<o)790 l->origin-=old;791 else if(a<=o)792 l->origin = a;793 if(a+old<l->p0)794 l->p0-=old;795 else if(a<=l->p0)796 l->p0 = a;797 if(a+old<l->p1)798 l->p1-=old;799 else if(a<=l->p1)800 l->p1 = a;801 }802 rresize(&t->rasp, a, old, 0L);803 rclean(&t->rasp);804 }