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