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