Blob
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;15 int inshort(void);16 long inlong(void);17 vlong invlong(void);18 int inmesg(Tmesg);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);27 void setgenstr(File*, Posn, Posn);29 #ifdef DEBUG30 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 };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 };85 void86 journal(int out, char *s)87 {88 static int fd = 0;90 if(fd <= 0)91 fd = create("/tmp/sam.out", 1, 0666L);92 fprint(fd, "%s%s\n", out? "out: " : "in: ", s);93 }95 void96 journaln(int out, long n)97 {98 char buf[32];100 snprint(buf, sizeof buf, "%ld", n);101 journal(out, buf);102 }104 void105 journalv(int out, vlong v)106 {107 char buf[32];109 snprint(buf, sizeof buf, "%lld", v);110 journal(out, buf);111 }113 #else114 #define journal(a, b)115 #define journaln(a, b)116 #endif118 int119 rcvchar(void){120 static uchar buf[64];121 static int i, nleft = 0;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 }133 int134 rcv(void){135 int c;136 static int state = 0;137 static int count = 0;138 static int i = 0;140 while((c=rcvchar()) != -1)141 switch(state){142 case 0:143 h.type = c;144 state++;145 break;147 case 1:148 h.count0 = c;149 state++;150 break;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;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 }176 File *177 whichfile(int tag)178 {179 int i;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 }188 int189 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;205 if(type > TMAX)206 panic("inmesg");208 journal(0, tname[type]);210 inp = indata;211 switch(type){212 case -1:213 panic("rcv error");215 default:216 fprint(2, "unknown type %d\n", type);217 panic("rcv unknown");219 case Tversion:220 tversion = inshort();221 journaln(0, tversion);222 break;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;243 case Tcheck:244 /* go through whichfile to check the tag */245 outTs(Hcheck, whichfile(inshort())->tag);246 break;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;272 case Torigin:273 s = inshort();274 l = inlong();275 l1 = inlong();276 journaln(0, l1);277 lookorigin(whichfile(s), l, l1);278 break;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;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;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 }else328 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;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;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;366 case Tsnarf:367 i = inshort();368 p0 = inlong();369 p1 = inlong();370 snarf(whichfile(i), p0, p1, &snarfbuf, 0);371 break;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;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;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;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;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;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;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;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 } else491 dprint("snarf buffer too long\n");492 break;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;512 case Tack:513 waitack = 0;514 break;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;567 case Texit:568 exits(0);569 }570 return TRUE;571 }573 void574 snarf(File *f, Posn p1, Posn p2, Buffer *buf, int emptyok)575 {576 Posn l;577 int i;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 }594 int595 inshort(void)596 {597 ushort n;599 n = inp[0] | (inp[1]<<8);600 inp += 2;601 return n;602 }604 long605 inlong(void)606 {607 ulong n;609 n = inp[0] | (inp[1]<<8) | (inp[2]<<16) | (inp[3]<<24);610 inp += 4;611 return n;612 }614 vlong615 invlong(void)616 {617 vlong v;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 }626 void627 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 }648 void649 outT0(Hmesg type)650 {651 outstart(type);652 outsend();653 }655 void656 outTl(Hmesg type, long l)657 {658 outstart(type);659 outlong(l);660 outsend();661 }663 void664 outTs(Hmesg type, int s)665 {666 outstart(type);667 journaln(1, s);668 outshort(s);669 outsend();670 }672 void673 outS(String *s)674 {675 char *c;676 int i;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 }688 void689 outTsS(Hmesg type, int s1, String *s)690 {691 outstart(type);692 outshort(s1);693 outS(s);694 outsend();695 }697 void698 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 }709 void710 outTS(Hmesg type, String *s)711 {712 outstart(type);713 outS(s);714 outsend();715 }717 void718 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 }730 void731 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 }742 void743 outTsl(Hmesg type, int s, Posn l)744 {745 outstart(type);746 outshort(s);747 outlong(l);748 journaln(1, l);749 outsend();750 }752 void753 outTsv(Hmesg type, int s, vlong v)754 {755 outstart(type);756 outshort(s);757 outvlong(v);758 journaln(1, v);759 outsend();760 }762 void763 outstart(Hmesg type)764 {765 journal(1, hname[type]);766 outmsg[0] = type;767 outp = outmsg+3;768 }770 void771 outcopy(int count, void *data)772 {773 memmove(outp, data, count);774 outp += count;775 }777 void778 outshort(int s)779 {780 *outp++ = s;781 *outp++ = s>>8;782 }784 void785 outlong(long l)786 {787 *outp++ = l;788 *outp++ = l>>8;789 *outp++ = l>>16;790 *outp++ = l>>24;791 }793 void794 outvlong(vlong v)795 {796 int i;798 for(i = 0; i < 8; i++){799 *outp++ = v;800 v >>= 8;801 }802 }804 void805 outsend(void)806 {807 int outcount;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 }825 int826 needoutflush(void)827 {828 return outmsg >= outdata+DATASIZE;829 }831 void832 outflush(void)833 {834 if(outmsg == outdata)835 return;836 outbuffered = 0;837 /* flow control */838 outT0(Hack);839 waitack = 1;840 do841 if(rcv() == 0){842 rescue();843 exits("eof");844 }845 while(waitack);846 outmsg = outdata;847 outbuffered = 1;848 }