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