1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <thread.h> 5 #include <cursor.h> 6 #include <mouse.h> 7 #include <keyboard.h> 8 #include <frame.h> 9 #include <plumb.h> 10 #include "flayer.h" 11 #include "samterm.h" 12 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 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**); 30 31 void 32 rcv(void) 33 { 34 int c; 35 static state = 0; 36 static count = 0; 37 static i = 0; 38 static int errs = 0; 39 40 while((c=rcvchar()) != -1) 41 switch(state){ 42 case 0: 43 h.type = c; 44 state++; 45 break; 46 47 case 1: 48 h.count0 = c; 49 state++; 50 break; 51 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; 69 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 } 82 83 Text * 84 whichtext(int tg) 85 { 86 int i; 87 88 for(i=0; i<nname; i++) 89 if(tag[i] == tg) 90 return text[i]; 91 panic("whichtext"); 92 return 0; 93 } 94 95 void 96 inmesg(Hmesg type, int count) 97 { 98 Text *t; 99 int i, m; 100 long l; 101 Flayer *lp; 102 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"); 111 112 case Hversion: 113 hversion = m; 114 break; 115 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; 129 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 }else 145 current(lp); 146 break; 147 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; 168 169 case Hgrow: 170 if(whichmenu(m) >= 0) 171 hgrow(m, l, inlong(6), 1); 172 break; 173 174 case Hnewname: 175 menuins(0, (uchar *)"", (Text *)0, ' ', m); 176 break; 177 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; 187 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; 197 198 case Hunlock: 199 clrlock(); 200 break; 201 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; 214 215 case Horigin: 216 if(whichmenu(m) >= 0) 217 horigin(m, l); 218 break; 219 220 case Hunlockfile: 221 if(whichmenu(m)>=0 && (t = whichtext(m))->lock){ 222 --t->lock; 223 l = -1; 224 goto Checkscroll; 225 } 226 break; 227 228 case Hsetdot: 229 if(whichmenu(m) >= 0) 230 hsetdot(m, l, inlong(6)); 231 break; 232 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; 240 241 case Hmoveto: 242 if(whichmenu(m)>=0) 243 hmoveto(m, l); 244 break; 245 246 case Hclean: 247 if((m = whichmenu(m)) >= 0) 248 name[m][0] = ' '; 249 break; 250 251 case Hdirty: 252 if((m = whichmenu(m))>=0) 253 name[m][0] = '\''; 254 break; 255 256 case Hdelname: 257 if((m=whichmenu(m)) >= 0) 258 menudel(m); 259 break; 260 261 case Hcut: 262 if(whichmenu(m) >= 0) 263 hcut(m, l, inlong(6)); 264 break; 265 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; 276 277 case Hsetpat: 278 setpat((char *)indata); 279 break; 280 281 case Hsetsnarf: 282 hsetsnarf(m); 283 break; 284 285 case Hsnarflen: 286 snarflen = inlong(0); 287 break; 288 289 case Hack: 290 outT0(Tack); 291 break; 292 293 case Hexit: 294 outT0(Texit); 295 threadexitsall(nil); 296 break; 297 298 case Hplumb: 299 hplumb(m); 300 break; 301 } 302 } 303 304 void 305 setlock(void) 306 { 307 hostlock++; 308 setcursor(mousectl, cursor = &lockarrow); 309 } 310 311 void 312 clrlock(void) 313 { 314 hasunlocked = 1; 315 if(hostlock > 0) 316 hostlock--; 317 if(hostlock == 0) 318 setcursor(mousectl, cursor=(Cursor *)0); 319 } 320 321 void 322 startfile(Text *t) 323 { 324 outTsv(Tstartfile, t->tag, t); /* for 64-bit pointers */ 325 setlock(); 326 } 327 328 void 329 startnewfile(int type, Text *t) 330 { 331 t->tag = Untagged; 332 outTv(type, t); /* for 64-bit pointers */ 333 } 334 335 int 336 inshort(int n) 337 { 338 return indata[n]|(indata[n+1]<<8); 339 } 340 341 long 342 inlong(int n) 343 { 344 return indata[n]|(indata[n+1]<<8)| 345 ((long)indata[n+2]<<16)|((long)indata[n+3]<<24); 346 } 347 348 long 349 invlong(int n) 350 { 351 long l; 352 353 l = (indata[n+7]<<24) | (indata[n+6]<<16) | (indata[n+5]<<8) | indata[n+4]; 354 l = (l<<16) | (indata[n+3]<<8) | indata[n+2]; 355 l = (l<<16) | (indata[n+1]<<8) | indata[n]; 356 return l; 357 } 358 359 void 360 outT0(Tmesg type) 361 { 362 outstart(type); 363 outsend(); 364 } 365 366 void 367 outTl(Tmesg type, long l) 368 { 369 outstart(type); 370 outlong(l); 371 outsend(); 372 } 373 374 void 375 outTs(Tmesg type, int s) 376 { 377 outstart(type); 378 outshort(s); 379 outsend(); 380 } 381 382 void 383 outTss(Tmesg type, int s1, int s2) 384 { 385 outstart(type); 386 outshort(s1); 387 outshort(s2); 388 outsend(); 389 } 390 391 void 392 outTsll(Tmesg type, int s1, long l1, long l2) 393 { 394 outstart(type); 395 outshort(s1); 396 outlong(l1); 397 outlong(l2); 398 outsend(); 399 } 400 401 void 402 outTsl(Tmesg type, int s1, long l1) 403 { 404 outstart(type); 405 outshort(s1); 406 outlong(l1); 407 outsend(); 408 } 409 410 void 411 outTsv(Tmesg type, int s1, void *l1) 412 { 413 outstart(type); 414 outshort(s1); 415 outvlong(l1); 416 outsend(); 417 } 418 419 void 420 outTv(Tmesg type, void *l1) 421 { 422 outstart(type); 423 outvlong(l1); 424 outsend(); 425 } 426 427 void 428 outTslS(Tmesg type, int s1, long l1, Rune *s) 429 { 430 char buf[DATASIZE*3+1]; 431 char *c; 432 433 outstart(type); 434 outshort(s1); 435 outlong(l1); 436 c = buf; 437 while(*s) 438 c += runetochar(c, s++); 439 *c++ = 0; 440 outcopy(c-buf, (uchar *)buf); 441 outsend(); 442 } 443 444 void 445 outTsls(Tmesg type, int s1, long l1, int s2) 446 { 447 outstart(type); 448 outshort(s1); 449 outlong(l1); 450 outshort(s2); 451 outsend(); 452 } 453 454 void 455 outstart(Tmesg type) 456 { 457 outdata[0] = type; 458 outcount = 0; 459 } 460 461 void 462 outcopy(int count, uchar *data) 463 { 464 while(count--) 465 outdata[HSIZE+outcount++] = *data++; 466 } 467 468 void 469 outshort(int s) 470 { 471 uchar buf[2]; 472 473 buf[0]=s; 474 buf[1]=s>>8; 475 outcopy(2, buf); 476 } 477 478 void 479 outlong(long l) 480 { 481 uchar buf[4]; 482 483 buf[0]=l; 484 buf[1]=l>>8; 485 buf[2]=l>>16; 486 buf[3]=l>>24; 487 outcopy(4, buf); 488 } 489 490 void 491 outvlong(void *v) 492 { 493 int i; 494 ulong l; 495 uchar buf[8]; 496 497 l = (ulong) v; 498 for(i = 0; i < sizeof(buf); i++, l >>= 8) 499 buf[i] = l; 500 501 outcopy(8, buf); 502 } 503 504 void 505 outsend(void) 506 { 507 if(outcount>DATASIZE-HSIZE) 508 panic("outcount>sizeof outdata"); 509 outdata[1]=outcount; 510 outdata[2]=outcount>>8; 511 if(write(1, (char *)outdata, outcount+HSIZE)!=outcount+HSIZE) 512 panic("write error"); 513 } 514 515 516 void 517 hsetdot(int m, long p0, long p1) 518 { 519 Text *t = whichtext(m); 520 Flayer *l = &t->l[t->front]; 521 522 flushtyping(1); 523 flsetselect(l, p0, p1); 524 } 525 526 void 527 horigin(int m, long p0) 528 { 529 Text *t = whichtext(m); 530 Flayer *l = &t->l[t->front]; 531 long a; 532 ulong n; 533 Rune *r; 534 535 if(!flprepare(l)){ 536 l->origin = p0; 537 return; 538 } 539 a = p0-l->origin; 540 if(a>=0 && a<l->f.nchars) 541 frdelete(&l->f, 0, a); 542 else if(a<0 && -a<l->f.nchars){ 543 r = rload(&t->rasp, p0, l->origin, &n); 544 frinsert(&l->f, r, r+n, 0); 545 }else 546 frdelete(&l->f, 0, l->f.nchars); 547 l->origin = p0; 548 scrdraw(l, t->rasp.nrunes); 549 if(l->visible==Some) 550 flrefresh(l, l->entire, 0); 551 hcheck(m); 552 } 553 554 void 555 hmoveto(int m, long p0) 556 { 557 Text *t = whichtext(m); 558 Flayer *l = &t->l[t->front]; 559 560 if(p0<l->origin || p0-l->origin>l->f.nchars*9/10) 561 outTsll(Torigin, m, p0, 2L); 562 } 563 564 void 565 hcheck(int m) 566 { 567 Flayer *l; 568 Text *t; 569 int reqd = 0, i; 570 long n, nl, a; 571 Rune *r; 572 573 if(m == Untagged) 574 return; 575 t = whichtext(m); 576 if(t == 0) /* possible in a half-built window */ 577 return; 578 for(l = &t->l[0], i = 0; i<NL; i++, l++){ 579 if(l->textfn==0 || !flprepare(l)) /* BUG: don't 580 need this if BUG below 581 is fixed */ 582 continue; 583 a = t->l[i].origin; 584 n = rcontig(&t->rasp, a, a+l->f.nchars, 1); 585 if(n<l->f.nchars) /* text missing in middle of screen */ 586 a+=n; 587 else{ /* text missing at end of screen? */ 588 Again: 589 if(l->f.lastlinefull) 590 goto Checksel; /* all's well */ 591 a = t->l[i].origin+l->f.nchars; 592 n = t->rasp.nrunes-a; 593 if(n==0) 594 goto Checksel; 595 if(n>TBLOCKSIZE) 596 n = TBLOCKSIZE; 597 n = rcontig(&t->rasp, a, a+n, 1); 598 if(n>0){ 599 rload(&t->rasp, a, a+n, 0); 600 nl = l->f.nchars; 601 r = scratch; 602 flinsert(l, r, r+n, l->origin+nl); 603 if(nl == l->f.nchars) /* made no progress */ 604 goto Checksel; 605 goto Again; 606 } 607 } 608 if(!reqd){ 609 n = rcontig(&t->rasp, a, a+TBLOCKSIZE, 0); 610 if(n <= 0) 611 panic("hcheck request==0"); 612 outTsls(Trequest, m, a, (int)n); 613 outTs(Tcheck, m); 614 t->lock++; /* for the Trequest */ 615 t->lock++; /* for the Tcheck */ 616 reqd++; 617 } 618 Checksel: 619 flsetselect(l, l->p0, l->p1); 620 } 621 } 622 623 void 624 flnewlyvisible(Flayer *l) 625 { 626 hcheck(((Text *)l->user1)->tag); 627 } 628 629 void 630 hsetsnarf(int nc) 631 { 632 char *s2; 633 char *s1; 634 int i; 635 int n; 636 637 setcursor(mousectl, &deadmouse); 638 s2 = alloc(nc+1); 639 for(i=0; i<nc; i++) 640 s2[i] = getch(); 641 s2[nc] = 0; 642 n = snarfswap(s2, nc, &s1); 643 if(n >= 0){ 644 if(!s1) 645 n = 0; 646 s1 = realloc(s1, n+1); 647 if (!s1) 648 panic("realloc"); 649 s1[n] = 0; 650 snarflen = n; 651 outTs(Tsetsnarf, n); 652 if(n>0 && write(1, s1, n)!=n) 653 panic("snarf write error"); 654 free(s1); 655 }else 656 outTs(Tsetsnarf, 0); 657 free(s2); 658 setcursor(mousectl, cursor); 659 } 660 661 void 662 hplumb(int nc) 663 { 664 int i; 665 char *s; 666 Plumbmsg *m; 667 668 s = alloc(nc); 669 for(i=0; i<nc; i++) 670 s[i] = getch(); 671 if(plumbfd > 0){ 672 m = plumbunpack(s, nc); 673 if(m != 0) 674 plumbsend(plumbfd, m); 675 plumbfree(m); 676 } 677 free(s); 678 } 679 680 void 681 hgrow(int m, long a, long new, int req) 682 { 683 int i; 684 Flayer *l; 685 Text *t = whichtext(m); 686 long o, b; 687 688 if(new <= 0) 689 panic("hgrow"); 690 rresize(&t->rasp, a, 0L, new); 691 for(l = &t->l[0], i = 0; i<NL; i++, l++){ 692 if(l->textfn == 0) 693 continue; 694 o = l->origin; 695 b = a-o-rmissing(&t->rasp, o, a); 696 if(a < o) 697 l->origin+=new; 698 if(a < l->p0) 699 l->p0+=new; 700 if(a < l->p1) 701 l->p1+=new; 702 /* must prevent b temporarily becoming unsigned */ 703 if(!req || a<o || (b>0 && b>l->f.nchars) || 704 (l->f.nchars==0 && a-o>0)) 705 continue; 706 if(new>TBLOCKSIZE) 707 new = TBLOCKSIZE; 708 outTsls(Trequest, m, a, (int)new); 709 t->lock++; 710 req = 0; 711 } 712 } 713 714 int 715 hdata1(Text *t, long a, Rune *r, int len) 716 { 717 int i; 718 Flayer *l; 719 long o, b; 720 721 for(l = &t->l[0], i=0; i<NL; i++, l++){ 722 if(l->textfn==0) 723 continue; 724 o = l->origin; 725 b = a-o-rmissing(&t->rasp, o, a); 726 /* must prevent b temporarily becoming unsigned */ 727 if(a<o || (b>0 && b>l->f.nchars)) 728 continue; 729 flinsert(l, r, r+len, o+b); 730 } 731 rdata(&t->rasp, a, a+len, r); 732 rclean(&t->rasp); 733 return len; 734 } 735 736 int 737 hdata(int m, long a, uchar *s, int len) 738 { 739 int i, w; 740 Text *t = whichtext(m); 741 Rune buf[DATASIZE], *r; 742 743 if(t->lock) 744 --t->lock; 745 if(len == 0) 746 return 0; 747 r = buf; 748 for(i=0; i<len; i+=w,s+=w) 749 w = chartorune(r++, (char*)s); 750 return hdata1(t, a, buf, r-buf); 751 } 752 753 int 754 hdatarune(int m, long a, Rune *r, int len) 755 { 756 Text *t = whichtext(m); 757 758 if(t->lock) 759 --t->lock; 760 if(len == 0) 761 return 0; 762 return hdata1(t, a, r, len); 763 } 764 765 void 766 hcut(int m, long a, long old) 767 { 768 Flayer *l; 769 Text *t = whichtext(m); 770 int i; 771 long o, b; 772 773 if(t->lock) 774 --t->lock; 775 for(l = &t->l[0], i = 0; i<NL; i++, l++){ 776 if(l->textfn == 0) 777 continue; 778 o = l->origin; 779 b = a-o-rmissing(&t->rasp, o, a); 780 /* must prevent b temporarily becoming unsigned */ 781 if((b<0 || b<l->f.nchars) && a+old>=o){ 782 fldelete(l, b<0? o : o+b, 783 a+old-rmissing(&t->rasp, o, a+old)); 784 } 785 if(a+old<o) 786 l->origin-=old; 787 else if(a<=o) 788 l->origin = a; 789 if(a+old<l->p0) 790 l->p0-=old; 791 else if(a<=l->p0) 792 l->p0 = a; 793 if(a+old<l->p1) 794 l->p1-=old; 795 else if(a<=l->p1) 796 l->p1 = a; 797 } 798 rresize(&t->rasp, a, old, 0L); 799 rclean(&t->rasp); 800 } 801