mesg.c (14442B)
1 #include "sam.h" 2 Header h; 3 uchar indata[DATASIZE]; 4 uchar outdata[2*DATASIZE+3]; /* room for overflow message */ 5 uchar *inp; 6 uchar *outp; 7 uchar *outmsg = outdata; 8 Posn cmdpt; 9 Posn cmdptadv; 10 Buffer snarfbuf; 11 int waitack; 12 int outbuffered; 13 int tversion; 14 15 int inshort(void); 16 long inlong(void); 17 vlong invlong(void); 18 int inmesg(Tmesg); 19 20 void outshort(int); 21 void outlong(long); 22 void outvlong(vlong); 23 void outcopy(int, void*); 24 void outsend(void); 25 void outstart(Hmesg); 26 27 void setgenstr(File*, Posn, Posn); 28 29 #ifdef DEBUG 30 char *hname[] = { 31 [Hversion] "Hversion", 32 [Hbindname] "Hbindname", 33 [Hcurrent] "Hcurrent", 34 [Hnewname] "Hnewname", 35 [Hmovname] "Hmovname", 36 [Hgrow] "Hgrow", 37 [Hcheck0] "Hcheck0", 38 [Hcheck] "Hcheck", 39 [Hunlock] "Hunlock", 40 [Hdata] "Hdata", 41 [Horigin] "Horigin", 42 [Hunlockfile] "Hunlockfile", 43 [Hsetdot] "Hsetdot", 44 [Hgrowdata] "Hgrowdata", 45 [Hmoveto] "Hmoveto", 46 [Hclean] "Hclean", 47 [Hdirty] "Hdirty", 48 [Hcut] "Hcut", 49 [Hsetpat] "Hsetpat", 50 [Hdelname] "Hdelname", 51 [Hclose] "Hclose", 52 [Hsetsnarf] "Hsetsnarf", 53 [Hsnarflen] "Hsnarflen", 54 [Hack] "Hack", 55 [Hexit] "Hexit", 56 // [Hplumb] "Hplumb" 57 }; 58 59 char *tname[] = { 60 [Tversion] "Tversion", 61 [Tstartcmdfile] "Tstartcmdfile", 62 [Tcheck] "Tcheck", 63 [Trequest] "Trequest", 64 [Torigin] "Torigin", 65 [Tstartfile] "Tstartfile", 66 [Tworkfile] "Tworkfile", 67 [Ttype] "Ttype", 68 [Tcut] "Tcut", 69 [Tpaste] "Tpaste", 70 [Tsnarf] "Tsnarf", 71 [Tstartnewfile] "Tstartnewfile", 72 [Twrite] "Twrite", 73 [Tclose] "Tclose", 74 [Tlook] "Tlook", 75 [Tsearch] "Tsearch", 76 [Tsend] "Tsend", 77 [Tdclick] "Tdclick", 78 [Tstartsnarf] "Tstartsnarf", 79 [Tsetsnarf] "Tsetsnarf", 80 [Tack] "Tack", 81 [Texit] "Texit", 82 // [Tplumb] "Tplumb" 83 }; 84 85 void 86 journal(int out, char *s) 87 { 88 static int fd = 0; 89 90 if(fd <= 0) 91 fd = create("/tmp/sam.out", 1, 0666L); 92 fprint(fd, "%s%s\n", out? "out: " : "in: ", s); 93 } 94 95 void 96 journaln(int out, long n) 97 { 98 char buf[32]; 99 100 snprint(buf, sizeof buf, "%ld", n); 101 journal(out, buf); 102 } 103 104 void 105 journalv(int out, vlong v) 106 { 107 char buf[32]; 108 109 snprint(buf, sizeof buf, "%lld", v); 110 journal(out, buf); 111 } 112 113 #else 114 #define journal(a, b) 115 #define journaln(a, b) 116 #endif 117 118 int 119 rcvchar(void){ 120 static uchar buf[64]; 121 static int i, nleft = 0; 122 123 if(nleft <= 0){ 124 nleft = read(0, (char *)buf, sizeof buf); 125 if(nleft <= 0) 126 return -1; 127 i = 0; 128 } 129 --nleft; 130 return buf[i++]; 131 } 132 133 int 134 rcv(void){ 135 int c; 136 static int state = 0; 137 static int count = 0; 138 static int i = 0; 139 140 while((c=rcvchar()) != -1) 141 switch(state){ 142 case 0: 143 h.type = c; 144 state++; 145 break; 146 147 case 1: 148 h.count0 = c; 149 state++; 150 break; 151 152 case 2: 153 h.count1 = c; 154 count = h.count0|(h.count1<<8); 155 i = 0; 156 if(count > DATASIZE) 157 panic("count>DATASIZE"); 158 if(count == 0) 159 goto zerocount; 160 state++; 161 break; 162 163 case 3: 164 indata[i++] = c; 165 if(i == count){ 166 zerocount: 167 indata[i] = 0; 168 state = count = 0; 169 return inmesg(h.type); 170 } 171 break; 172 } 173 return 0; 174 } 175 176 File * 177 whichfile(int tag) 178 { 179 int i; 180 181 for(i = 0; i<file.nused; i++) 182 if(file.filepptr[i]->tag==tag) 183 return file.filepptr[i]; 184 hiccough((char *)0); 185 return 0; 186 } 187 188 int 189 inmesg(Tmesg type) 190 { 191 Rune buf[1025]; 192 char cbuf[64]; 193 int i, m; 194 short s; 195 long l, l1; 196 vlong v; 197 File *f; 198 Posn p0, p1, p; 199 Range r; 200 String *str; 201 char *c, *wdir; 202 Rune *rp; 203 Plumbmsg *pm; 204 205 if(type > TMAX) 206 panic("inmesg"); 207 208 journal(0, tname[type]); 209 210 inp = indata; 211 switch(type){ 212 case -1: 213 panic("rcv error"); 214 215 default: 216 fprint(2, "unknown type %d\n", type); 217 panic("rcv unknown"); 218 219 case Tversion: 220 tversion = inshort(); 221 journaln(0, tversion); 222 break; 223 224 case Tstartcmdfile: 225 v = invlong(); /* for 64-bit pointers */ 226 journaln(0, v); 227 Strdupl(&genstr, samname); 228 cmd = newfile(); 229 cmd->unread = 0; 230 outTsv(Hbindname, cmd->tag, v); 231 outTs(Hcurrent, cmd->tag); 232 logsetname(cmd, &genstr); 233 cmd->rasp = listalloc('P'); 234 cmd->mod = 0; 235 if(cmdstr.n){ 236 loginsert(cmd, 0L, cmdstr.s, cmdstr.n); 237 Strdelete(&cmdstr, 0L, (Posn)cmdstr.n); 238 } 239 fileupdate(cmd, FALSE, TRUE); 240 outT0(Hunlock); 241 break; 242 243 case Tcheck: 244 /* go through whichfile to check the tag */ 245 outTs(Hcheck, whichfile(inshort())->tag); 246 break; 247 248 case Trequest: 249 f = whichfile(inshort()); 250 p0 = inlong(); 251 p1 = p0+inshort(); 252 journaln(0, p0); 253 journaln(0, p1-p0); 254 if(f->unread) 255 panic("Trequest: unread"); 256 if(p1>f->b.nc) 257 p1 = f->b.nc; 258 if(p0>f->b.nc) /* can happen e.g. scrolling during command */ 259 p0 = f->b.nc; 260 if(p0 == p1){ 261 i = 0; 262 r.p1 = r.p2 = p0; 263 }else{ 264 r = rdata(f->rasp, p0, p1-p0); 265 i = r.p2-r.p1; 266 bufread(&f->b, r.p1, buf, i); 267 } 268 buf[i]=0; 269 outTslS(Hdata, f->tag, r.p1, tmprstr(buf, i+1)); 270 break; 271 272 case Torigin: 273 s = inshort(); 274 l = inlong(); 275 l1 = inlong(); 276 journaln(0, l1); 277 lookorigin(whichfile(s), l, l1); 278 break; 279 280 case Tstartfile: 281 termlocked++; 282 f = whichfile(inshort()); 283 if(!f->rasp) /* this might be a duplicate message */ 284 f->rasp = listalloc('P'); 285 current(f); 286 outTsv(Hbindname, f->tag, invlong()); /* for 64-bit pointers */ 287 outTs(Hcurrent, f->tag); 288 journaln(0, f->tag); 289 if(f->unread) 290 load(f); 291 else{ 292 if(f->b.nc>0){ 293 rgrow(f->rasp, 0L, f->b.nc); 294 outTsll(Hgrow, f->tag, 0L, f->b.nc); 295 } 296 outTs(Hcheck0, f->tag); 297 moveto(f, f->dot.r); 298 } 299 break; 300 301 case Tworkfile: 302 i = inshort(); 303 f = whichfile(i); 304 current(f); 305 f->dot.r.p1 = inlong(); 306 f->dot.r.p2 = inlong(); 307 f->tdot = f->dot.r; 308 journaln(0, i); 309 journaln(0, f->dot.r.p1); 310 journaln(0, f->dot.r.p2); 311 break; 312 313 case Ttype: 314 f = whichfile(inshort()); 315 p0 = inlong(); 316 journaln(0, p0); 317 journal(0, (char*)inp); 318 str = tmpcstr((char*)inp); 319 i = str->n; 320 loginsert(f, p0, str->s, str->n); 321 if(fileupdate(f, FALSE, FALSE)) 322 seq++; 323 if(f==cmd && p0==f->b.nc-i && i>0 && str->s[i-1]=='\n'){ 324 freetmpstr(str); 325 termlocked++; 326 termcommand(); 327 }else 328 freetmpstr(str); 329 f->dot.r.p1 = f->dot.r.p2 = p0+i; /* terminal knows this already */ 330 f->tdot = f->dot.r; 331 break; 332 333 case Tcut: 334 f = whichfile(inshort()); 335 p0 = inlong(); 336 p1 = inlong(); 337 journaln(0, p0); 338 journaln(0, p1); 339 logdelete(f, p0, p1); 340 if(fileupdate(f, FALSE, FALSE)) 341 seq++; 342 f->dot.r.p1 = f->dot.r.p2 = p0; 343 f->tdot = f->dot.r; /* terminal knows the value of dot already */ 344 break; 345 346 case Tpaste: 347 f = whichfile(inshort()); 348 p0 = inlong(); 349 journaln(0, p0); 350 for(l=0; l<snarfbuf.nc; l+=m){ 351 m = snarfbuf.nc-l; 352 if(m>BLOCKSIZE) 353 m = BLOCKSIZE; 354 bufread(&snarfbuf, l, genbuf, m); 355 loginsert(f, p0, tmprstr(genbuf, m)->s, m); 356 } 357 if(fileupdate(f, FALSE, TRUE)) 358 seq++; 359 f->dot.r.p1 = p0; 360 f->dot.r.p2 = p0+snarfbuf.nc; 361 f->tdot.p1 = -1; /* force telldot to tell (arguably a BUG) */ 362 telldot(f); 363 outTs(Hunlockfile, f->tag); 364 break; 365 366 case Tsnarf: 367 i = inshort(); 368 p0 = inlong(); 369 p1 = inlong(); 370 snarf(whichfile(i), p0, p1, &snarfbuf, 0); 371 break; 372 373 case Tstartnewfile: 374 v = invlong(); 375 Strdupl(&genstr, empty); 376 f = newfile(); 377 f->rasp = listalloc('P'); 378 outTsv(Hbindname, f->tag, v); 379 logsetname(f, &genstr); 380 outTs(Hcurrent, f->tag); 381 current(f); 382 load(f); 383 break; 384 385 case Twrite: 386 termlocked++; 387 i = inshort(); 388 journaln(0, i); 389 f = whichfile(i); 390 addr.r.p1 = 0; 391 addr.r.p2 = f->b.nc; 392 if(f->name.s[0] == 0) 393 error(Enoname); 394 Strduplstr(&genstr, &f->name); 395 writef(f); 396 break; 397 398 case Tclose: 399 termlocked++; 400 i = inshort(); 401 journaln(0, i); 402 f = whichfile(i); 403 current(f); 404 trytoclose(f); 405 /* if trytoclose fails, will error out */ 406 delete(f); 407 break; 408 409 case Tlook: 410 f = whichfile(inshort()); 411 termlocked++; 412 p0 = inlong(); 413 p1 = inlong(); 414 journaln(0, p0); 415 journaln(0, p1); 416 setgenstr(f, p0, p1); 417 for(l = 0; l<genstr.n; l++){ 418 i = genstr.s[l]; 419 if(utfrune(".*+?(|)\\[]^$", i)){ 420 str = tmpcstr("\\"); 421 Strinsert(&genstr, str, l++); 422 freetmpstr(str); 423 } 424 } 425 Straddc(&genstr, '\0'); 426 nextmatch(f, &genstr, p1, 1); 427 moveto(f, sel.p[0]); 428 break; 429 430 case Tsearch: 431 termlocked++; 432 if(curfile == 0) 433 error(Enofile); 434 if(lastpat.s[0] == 0) 435 panic("Tsearch"); 436 nextmatch(curfile, &lastpat, curfile->dot.r.p2, 1); 437 moveto(curfile, sel.p[0]); 438 break; 439 440 case Tsend: 441 termlocked++; 442 inshort(); /* ignored */ 443 p0 = inlong(); 444 p1 = inlong(); 445 setgenstr(cmd, p0, p1); 446 bufreset(&snarfbuf); 447 bufinsert(&snarfbuf, (Posn)0, genstr.s, genstr.n); 448 outTl(Hsnarflen, genstr.n); 449 if(genstr.s[genstr.n-1] != '\n') 450 Straddc(&genstr, '\n'); 451 loginsert(cmd, cmd->b.nc, genstr.s, genstr.n); 452 fileupdate(cmd, FALSE, TRUE); 453 cmd->dot.r.p1 = cmd->dot.r.p2 = cmd->b.nc; 454 telldot(cmd); 455 termcommand(); 456 break; 457 458 case Tdclick: 459 f = whichfile(inshort()); 460 p1 = inlong(); 461 doubleclick(f, p1); 462 f->tdot.p1 = f->tdot.p2 = p1; 463 telldot(f); 464 outTs(Hunlockfile, f->tag); 465 break; 466 467 case Tstartsnarf: 468 if (snarfbuf.nc <= 0) { /* nothing to export */ 469 outTs(Hsetsnarf, 0); 470 break; 471 } 472 c = 0; 473 i = 0; 474 m = snarfbuf.nc; 475 if(m > SNARFSIZE) { 476 m = SNARFSIZE; 477 dprint("?warning: snarf buffer truncated\n"); 478 } 479 rp = malloc(m*sizeof(Rune)); 480 if(rp){ 481 bufread(&snarfbuf, 0, rp, m); 482 c = Strtoc(tmprstr(rp, m)); 483 free(rp); 484 i = strlen(c); 485 } 486 outTs(Hsetsnarf, i); 487 if(c){ 488 Write(1, c, i); 489 free(c); 490 } else 491 dprint("snarf buffer too long\n"); 492 break; 493 494 case Tsetsnarf: 495 m = inshort(); 496 if(m > SNARFSIZE) 497 error(Etoolong); 498 c = malloc(m+1); 499 if(c){ 500 for(i=0; i<m; i++) 501 c[i] = rcvchar(); 502 c[m] = 0; 503 str = tmpcstr(c); 504 free(c); 505 bufreset(&snarfbuf); 506 bufinsert(&snarfbuf, (Posn)0, str->s, str->n); 507 freetmpstr(str); 508 outT0(Hunlock); 509 } 510 break; 511 512 case Tack: 513 waitack = 0; 514 break; 515 #if 0 516 case Tplumb: 517 f = whichfile(inshort()); 518 p0 = inlong(); 519 p1 = inlong(); 520 pm = emalloc(sizeof(Plumbmsg)); 521 pm->src = strdup("sam"); 522 pm->dst = 0; 523 /* construct current directory */ 524 c = Strtoc(&f->name); 525 if(c[0] == '/') 526 pm->wdir = c; 527 else{ 528 wdir = emalloc(1024); 529 getwd(wdir, 1024); 530 pm->wdir = emalloc(1024); 531 snprint(pm->wdir, 1024, "%s/%s", wdir, c); 532 cleanname(pm->wdir); 533 free(wdir); 534 free(c); 535 } 536 c = strrchr(pm->wdir, '/'); 537 if(c) 538 *c = '\0'; 539 pm->type = strdup("text"); 540 if(p1 > p0) 541 pm->attr = nil; 542 else{ 543 p = p0; 544 while(p0>0 && (i=filereadc(f, p0 - 1))!=' ' && i!='\t' && i!='\n') 545 p0--; 546 while(p1<f->b.nc && (i=filereadc(f, p1))!=' ' && i!='\t' && i!='\n') 547 p1++; 548 sprint(cbuf, "click=%ld", p-p0); 549 pm->attr = plumbunpackattr(cbuf); 550 } 551 if(p0==p1 || p1-p0>=BLOCKSIZE){ 552 plumbfree(pm); 553 break; 554 } 555 setgenstr(f, p0, p1); 556 pm->data = Strtoc(&genstr); 557 pm->ndata = strlen(pm->data); 558 c = plumbpack(pm, &i); 559 if(c != 0){ 560 outTs(Hplumb, i); 561 Write(1, c, i); 562 free(c); 563 } 564 plumbfree(pm); 565 break; 566 #endif 567 case Texit: 568 exits(0); 569 } 570 return TRUE; 571 } 572 573 void 574 snarf(File *f, Posn p1, Posn p2, Buffer *buf, int emptyok) 575 { 576 Posn l; 577 int i; 578 579 if(!emptyok && p1==p2) 580 return; 581 bufreset(buf); 582 /* Stage through genbuf to avoid compaction problems (vestigial) */ 583 if(p2 > f->b.nc){ 584 fprint(2, "bad snarf addr p1=%ld p2=%ld f->b.nc=%d\n", p1, p2, f->b.nc); /*ZZZ should never happen, can remove */ 585 p2 = f->b.nc; 586 } 587 for(l=p1; l<p2; l+=i){ 588 i = p2-l>BLOCKSIZE? BLOCKSIZE : p2-l; 589 bufread(&f->b, l, genbuf, i); 590 bufinsert(buf, buf->nc, tmprstr(genbuf, i)->s, i); 591 } 592 } 593 594 int 595 inshort(void) 596 { 597 ushort n; 598 599 n = inp[0] | (inp[1]<<8); 600 inp += 2; 601 return n; 602 } 603 604 long 605 inlong(void) 606 { 607 ulong n; 608 609 n = inp[0] | (inp[1]<<8) | (inp[2]<<16) | (inp[3]<<24); 610 inp += 4; 611 return n; 612 } 613 614 vlong 615 invlong(void) 616 { 617 vlong v; 618 619 v = (inp[7]<<24) | (inp[6]<<16) | (inp[5]<<8) | inp[4]; 620 v = (v<<16) | (inp[3]<<8) | inp[2]; 621 v = (v<<16) | (inp[1]<<8) | inp[0]; 622 inp += 8; 623 return v; 624 } 625 626 void 627 setgenstr(File *f, Posn p0, Posn p1) 628 { 629 if(p0 != p1){ 630 if(p1-p0 >= TBLOCKSIZE) 631 error(Etoolong); 632 Strinsure(&genstr, p1-p0); 633 bufread(&f->b, p0, genbuf, p1-p0); 634 memmove(genstr.s, genbuf, RUNESIZE*(p1-p0)); 635 genstr.n = p1-p0; 636 }else{ 637 if(snarfbuf.nc == 0) 638 error(Eempty); 639 if(snarfbuf.nc > TBLOCKSIZE) 640 error(Etoolong); 641 bufread(&snarfbuf, (Posn)0, genbuf, snarfbuf.nc); 642 Strinsure(&genstr, snarfbuf.nc); 643 memmove(genstr.s, genbuf, RUNESIZE*snarfbuf.nc); 644 genstr.n = snarfbuf.nc; 645 } 646 } 647 648 void 649 outT0(Hmesg type) 650 { 651 outstart(type); 652 outsend(); 653 } 654 655 void 656 outTl(Hmesg type, long l) 657 { 658 outstart(type); 659 outlong(l); 660 outsend(); 661 } 662 663 void 664 outTs(Hmesg type, int s) 665 { 666 outstart(type); 667 journaln(1, s); 668 outshort(s); 669 outsend(); 670 } 671 672 void 673 outS(String *s) 674 { 675 char *c; 676 int i; 677 678 c = Strtoc(s); 679 i = strlen(c); 680 outcopy(i, c); 681 if(i > 99) 682 c[99] = 0; 683 journaln(1, i); 684 journal(1, c); 685 free(c); 686 } 687 688 void 689 outTsS(Hmesg type, int s1, String *s) 690 { 691 outstart(type); 692 outshort(s1); 693 outS(s); 694 outsend(); 695 } 696 697 void 698 outTslS(Hmesg type, int s1, Posn l1, String *s) 699 { 700 outstart(type); 701 outshort(s1); 702 journaln(1, s1); 703 outlong(l1); 704 journaln(1, l1); 705 outS(s); 706 outsend(); 707 } 708 709 void 710 outTS(Hmesg type, String *s) 711 { 712 outstart(type); 713 outS(s); 714 outsend(); 715 } 716 717 void 718 outTsllS(Hmesg type, int s1, Posn l1, Posn l2, String *s) 719 { 720 outstart(type); 721 outshort(s1); 722 outlong(l1); 723 outlong(l2); 724 journaln(1, l1); 725 journaln(1, l2); 726 outS(s); 727 outsend(); 728 } 729 730 void 731 outTsll(Hmesg type, int s, Posn l1, Posn l2) 732 { 733 outstart(type); 734 outshort(s); 735 outlong(l1); 736 outlong(l2); 737 journaln(1, l1); 738 journaln(1, l2); 739 outsend(); 740 } 741 742 void 743 outTsl(Hmesg type, int s, Posn l) 744 { 745 outstart(type); 746 outshort(s); 747 outlong(l); 748 journaln(1, l); 749 outsend(); 750 } 751 752 void 753 outTsv(Hmesg type, int s, vlong v) 754 { 755 outstart(type); 756 outshort(s); 757 outvlong(v); 758 journaln(1, v); 759 outsend(); 760 } 761 762 void 763 outstart(Hmesg type) 764 { 765 journal(1, hname[type]); 766 outmsg[0] = type; 767 outp = outmsg+3; 768 } 769 770 void 771 outcopy(int count, void *data) 772 { 773 memmove(outp, data, count); 774 outp += count; 775 } 776 777 void 778 outshort(int s) 779 { 780 *outp++ = s; 781 *outp++ = s>>8; 782 } 783 784 void 785 outlong(long l) 786 { 787 *outp++ = l; 788 *outp++ = l>>8; 789 *outp++ = l>>16; 790 *outp++ = l>>24; 791 } 792 793 void 794 outvlong(vlong v) 795 { 796 int i; 797 798 for(i = 0; i < 8; i++){ 799 *outp++ = v; 800 v >>= 8; 801 } 802 } 803 804 void 805 outsend(void) 806 { 807 int outcount; 808 809 if(outp >= outdata+nelem(outdata)) 810 panic("outsend"); 811 outcount = outp-outmsg; 812 outcount -= 3; 813 outmsg[1] = outcount; 814 outmsg[2] = outcount>>8; 815 outmsg = outp; 816 if(!outbuffered){ 817 outcount = outmsg-outdata; 818 if (write(1, (char*) outdata, outcount) != outcount) 819 rescue(); 820 outmsg = outdata; 821 return; 822 } 823 } 824 825 int 826 needoutflush(void) 827 { 828 return outmsg >= outdata+DATASIZE; 829 } 830 831 void 832 outflush(void) 833 { 834 if(outmsg == outdata) 835 return; 836 outbuffered = 0; 837 /* flow control */ 838 outT0(Hack); 839 waitack = 1; 840 do 841 if(rcv() == 0){ 842 rescue(); 843 exits("eof"); 844 } 845 while(waitack); 846 outmsg = outdata; 847 outbuffered = 1; 848 }