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