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