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 str = tmpcstr("\\");403 Strinsert(&genstr, str, l++);404 freetmpstr(str);405 }406 }407 Straddc(&genstr, '\0');408 nextmatch(f, &genstr, p1, 1);409 moveto(f, sel.p[0]);410 break;412 case Tsearch:413 termlocked++;414 if(curfile == 0)415 error(Enofile);416 if(lastpat.s[0] == 0)417 panic("Tsearch");418 nextmatch(curfile, &lastpat, curfile->dot.r.p2, 1);419 moveto(curfile, sel.p[0]);420 break;422 case Tsend:423 termlocked++;424 inshort(); /* ignored */425 p0 = inlong();426 p1 = inlong();427 setgenstr(cmd, p0, p1);428 bufreset(&snarfbuf);429 bufinsert(&snarfbuf, (Posn)0, genstr.s, genstr.n);430 outTl(Hsnarflen, genstr.n);431 if(genstr.s[genstr.n-1] != '\n')432 Straddc(&genstr, '\n');433 loginsert(cmd, cmd->b.nc, genstr.s, genstr.n);434 fileupdate(cmd, FALSE, TRUE);435 cmd->dot.r.p1 = cmd->dot.r.p2 = cmd->b.nc;436 telldot(cmd);437 termcommand();438 break;440 case Tdclick:441 f = whichfile(inshort());442 p1 = inlong();443 doubleclick(f, p1);444 f->tdot.p1 = f->tdot.p2 = p1;445 telldot(f);446 outTs(Hunlockfile, f->tag);447 break;449 case Tstartsnarf:450 if (snarfbuf.nc <= 0) { /* nothing to export */451 outTs(Hsetsnarf, 0);452 break;453 }454 c = 0;455 i = 0;456 m = snarfbuf.nc;457 if(m > SNARFSIZE) {458 m = SNARFSIZE;459 dprint("?warning: snarf buffer truncated\n");460 }461 rp = malloc(m*sizeof(Rune));462 if(rp){463 bufread(&snarfbuf, 0, rp, m);464 c = Strtoc(tmprstr(rp, m));465 free(rp);466 i = strlen(c);467 }468 outTs(Hsetsnarf, i);469 if(c){470 Write(1, c, i);471 free(c);472 } else473 dprint("snarf buffer too long\n");474 break;476 case Tsetsnarf:477 m = inshort();478 if(m > SNARFSIZE)479 error(Etoolong);480 c = malloc(m+1);481 if(c){482 for(i=0; i<m; i++)483 c[i] = rcvchar();484 c[m] = 0;485 str = tmpcstr(c);486 free(c);487 bufreset(&snarfbuf);488 bufinsert(&snarfbuf, (Posn)0, str->s, str->n);489 freetmpstr(str);490 outT0(Hunlock);491 }492 break;494 case Tack:495 waitack = 0;496 break;498 case Tplumb:499 f = whichfile(inshort());500 p0 = inlong();501 p1 = inlong();502 pm = emalloc(sizeof(Plumbmsg));503 pm->src = strdup("sam");504 pm->dst = 0;505 /* construct current directory */506 c = Strtoc(&f->name);507 if(c[0] == '/')508 pm->wdir = c;509 else{510 wdir = emalloc(1024);511 getwd(wdir, 1024);512 pm->wdir = emalloc(1024);513 snprint(pm->wdir, 1024, "%s/%s", wdir, c);514 cleanname(pm->wdir);515 free(wdir);516 free(c);517 }518 c = strrchr(pm->wdir, '/');519 if(c)520 *c = '\0';521 pm->type = strdup("text");522 if(p1 > p0)523 pm->attr = nil;524 else{525 p = p0;526 while(p0>0 && (i=filereadc(f, p0 - 1))!=' ' && i!='\t' && i!='\n')527 p0--;528 while(p1<f->b.nc && (i=filereadc(f, p1))!=' ' && i!='\t' && i!='\n')529 p1++;530 sprint(cbuf, "click=%ld", p-p0);531 pm->attr = plumbunpackattr(cbuf);532 }533 if(p0==p1 || p1-p0>=BLOCKSIZE){534 plumbfree(pm);535 break;536 }537 setgenstr(f, p0, p1);538 pm->data = Strtoc(&genstr);539 pm->ndata = strlen(pm->data);540 c = plumbpack(pm, &i);541 if(c != 0){542 outTs(Hplumb, i);543 Write(1, c, i);544 free(c);545 }546 plumbfree(pm);547 break;549 case Texit:550 exits(0);551 }552 return TRUE;553 }555 void556 snarf(File *f, Posn p1, Posn p2, Buffer *buf, int emptyok)557 {558 Posn l;559 int i;561 if(!emptyok && p1==p2)562 return;563 bufreset(buf);564 /* Stage through genbuf to avoid compaction problems (vestigial) */565 if(p2 > f->b.nc){566 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 */567 p2 = f->b.nc;568 }569 for(l=p1; l<p2; l+=i){570 i = p2-l>BLOCKSIZE? BLOCKSIZE : p2-l;571 bufread(&f->b, l, genbuf, i);572 bufinsert(buf, buf->nc, tmprstr(genbuf, i)->s, i);573 }574 }576 int577 inshort(void)578 {579 ushort n;581 n = inp[0] | (inp[1]<<8);582 inp += 2;583 return n;584 }586 long587 inlong(void)588 {589 ulong n;591 n = inp[0] | (inp[1]<<8) | (inp[2]<<16) | (inp[3]<<24);592 inp += 4;593 return n;594 }596 long597 invlong(void)598 {599 ulong n;601 n = (inp[7]<<24) | (inp[6]<<16) | (inp[5]<<8) | inp[4];602 n = (n<<16) | (inp[3]<<8) | inp[2];603 n = (n<<16) | (inp[1]<<8) | inp[0];604 inp += 8;605 return n;606 }608 void609 setgenstr(File *f, Posn p0, Posn p1)610 {611 if(p0 != p1){612 if(p1-p0 >= TBLOCKSIZE)613 error(Etoolong);614 Strinsure(&genstr, p1-p0);615 bufread(&f->b, p0, genbuf, p1-p0);616 memmove(genstr.s, genbuf, RUNESIZE*(p1-p0));617 genstr.n = p1-p0;618 }else{619 if(snarfbuf.nc == 0)620 error(Eempty);621 if(snarfbuf.nc > TBLOCKSIZE)622 error(Etoolong);623 bufread(&snarfbuf, (Posn)0, genbuf, snarfbuf.nc);624 Strinsure(&genstr, snarfbuf.nc);625 memmove(genstr.s, genbuf, RUNESIZE*snarfbuf.nc);626 genstr.n = snarfbuf.nc;627 }628 }630 void631 outT0(Hmesg type)632 {633 outstart(type);634 outsend();635 }637 void638 outTl(Hmesg type, long l)639 {640 outstart(type);641 outlong(l);642 outsend();643 }645 void646 outTs(Hmesg type, int s)647 {648 outstart(type);649 journaln(1, s);650 outshort(s);651 outsend();652 }654 void655 outS(String *s)656 {657 char *c;658 int i;660 c = Strtoc(s);661 i = strlen(c);662 outcopy(i, c);663 if(i > 99)664 c[99] = 0;665 journaln(1, i);666 journal(1, c);667 free(c);668 }670 void671 outTsS(Hmesg type, int s1, String *s)672 {673 outstart(type);674 outshort(s1);675 outS(s);676 outsend();677 }679 void680 outTslS(Hmesg type, int s1, Posn l1, String *s)681 {682 outstart(type);683 outshort(s1);684 journaln(1, s1);685 outlong(l1);686 journaln(1, l1);687 outS(s);688 outsend();689 }691 void692 outTS(Hmesg type, String *s)693 {694 outstart(type);695 outS(s);696 outsend();697 }699 void700 outTsllS(Hmesg type, int s1, Posn l1, Posn l2, String *s)701 {702 outstart(type);703 outshort(s1);704 outlong(l1);705 outlong(l2);706 journaln(1, l1);707 journaln(1, l2);708 outS(s);709 outsend();710 }712 void713 outTsll(Hmesg type, int s, Posn l1, Posn l2)714 {715 outstart(type);716 outshort(s);717 outlong(l1);718 outlong(l2);719 journaln(1, l1);720 journaln(1, l2);721 outsend();722 }724 void725 outTsl(Hmesg type, int s, Posn l)726 {727 outstart(type);728 outshort(s);729 outlong(l);730 journaln(1, l);731 outsend();732 }734 void735 outTsv(Hmesg type, int s, Posn l)736 {737 outstart(type);738 outshort(s);739 outvlong((void*)l);740 journaln(1, l);741 outsend();742 }744 void745 outstart(Hmesg type)746 {747 journal(1, hname[type]);748 outmsg[0] = type;749 outp = outmsg+3;750 }752 void753 outcopy(int count, void *data)754 {755 memmove(outp, data, count);756 outp += count;757 }759 void760 outshort(int s)761 {762 *outp++ = s;763 *outp++ = s>>8;764 }766 void767 outlong(long l)768 {769 *outp++ = l;770 *outp++ = l>>8;771 *outp++ = l>>16;772 *outp++ = l>>24;773 }775 void776 outvlong(void *v)777 {778 int i;779 ulong l;781 l = (ulong) v;782 for(i = 0; i < 8; i++, l >>= 8)783 *outp++ = l;784 }786 void787 outsend(void)788 {789 int outcount;791 outcount = outp-outmsg;792 outcount -= 3;793 outmsg[1] = outcount;794 outmsg[2] = outcount>>8;795 outmsg = outp;796 if(!noflush){797 outcount = outmsg-outdata;798 if (write(1, (char*) outdata, outcount) != outcount)799 rescue();800 outmsg = outdata;801 return;802 }803 if(outmsg < outdata+DATASIZE)804 return;805 outflush();806 }808 void809 outflush(void)810 {811 if(outmsg == outdata)812 return;813 noflush = 0;814 outT0(Hack);815 waitack = 1;816 do817 if(rcv() == 0){818 rescue();819 exits("eof");820 }821 while(waitack);822 outmsg = outdata;823 noflush = 1;824 }