Blob


1 #include "sam.h"
2 #define DEBUG
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 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 DEBUG
31 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 void
87 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 void
97 journaln(int out, long n)
98 {
99 char buf[32];
101 snprint(buf, sizeof buf, "%ld", n);
102 journal(out, buf);
105 void
106 journalv(int out, vlong v)
108 char buf[32];
110 snprint(buf, sizeof buf, "%lld", v);
111 journal(out, buf);
114 #else
115 #define journal(a, b)
116 #define journaln(a, b)
117 #endif
119 int
120 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;
130 --nleft;
131 return buf[i++];
134 int
135 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);
172 break;
174 return 0;
177 File *
178 whichfile(int tag)
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;
189 int
190 inmesg(Tmesg type)
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);
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);
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);
297 outTs(Hcheck0, f->tag);
298 moveto(f, f->dot.r);
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 }else
329 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);
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);
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;
473 c = 0;
474 i = 0;
475 m = snarfbuf.nc;
476 if(m > SNARFSIZE) {
477 m = SNARFSIZE;
478 dprint("?warning: snarf buffer truncated\n");
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);
487 outTs(Hsetsnarf, i);
488 if(c){
489 Write(1, c, i);
490 free(c);
491 } else
492 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);
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);
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);
552 if(p0==p1 || p1-p0>=BLOCKSIZE){
553 plumbfree(pm);
554 break;
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);
565 plumbfree(pm);
566 break;
568 case Texit:
569 exits(0);
571 return TRUE;
574 void
575 snarf(File *f, Posn p1, Posn p2, Buffer *buf, int emptyok)
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;
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);
595 int
596 inshort(void)
598 ushort n;
600 n = inp[0] | (inp[1]<<8);
601 inp += 2;
602 return n;
605 long
606 inlong(void)
608 ulong n;
610 n = inp[0] | (inp[1]<<8) | (inp[2]<<16) | (inp[3]<<24);
611 inp += 4;
612 return n;
615 vlong
616 invlong(void)
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;
627 void
628 setgenstr(File *f, Posn p0, Posn p1)
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;
649 void
650 outT0(Hmesg type)
652 outstart(type);
653 outsend();
656 void
657 outTl(Hmesg type, long l)
659 outstart(type);
660 outlong(l);
661 outsend();
664 void
665 outTs(Hmesg type, int s)
667 outstart(type);
668 journaln(1, s);
669 outshort(s);
670 outsend();
673 void
674 outS(String *s)
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);
689 void
690 outTsS(Hmesg type, int s1, String *s)
692 outstart(type);
693 outshort(s1);
694 outS(s);
695 outsend();
698 void
699 outTslS(Hmesg type, int s1, Posn l1, String *s)
701 outstart(type);
702 outshort(s1);
703 journaln(1, s1);
704 outlong(l1);
705 journaln(1, l1);
706 outS(s);
707 outsend();
710 void
711 outTS(Hmesg type, String *s)
713 outstart(type);
714 outS(s);
715 outsend();
718 void
719 outTsllS(Hmesg type, int s1, Posn l1, Posn l2, String *s)
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();
731 void
732 outTsll(Hmesg type, int s, Posn l1, Posn l2)
734 outstart(type);
735 outshort(s);
736 outlong(l1);
737 outlong(l2);
738 journaln(1, l1);
739 journaln(1, l2);
740 outsend();
743 void
744 outTsl(Hmesg type, int s, Posn l)
746 outstart(type);
747 outshort(s);
748 outlong(l);
749 journaln(1, l);
750 outsend();
753 void
754 outTsv(Hmesg type, int s, vlong v)
756 outstart(type);
757 outshort(s);
758 outvlong(v);
759 journaln(1, v);
760 outsend();
763 void
764 outstart(Hmesg type)
766 journal(1, hname[type]);
767 outmsg[0] = type;
768 outp = outmsg+3;
771 void
772 outcopy(int count, void *data)
774 memmove(outp, data, count);
775 outp += count;
778 void
779 outshort(int s)
781 *outp++ = s;
782 *outp++ = s>>8;
785 void
786 outlong(long l)
788 *outp++ = l;
789 *outp++ = l>>8;
790 *outp++ = l>>16;
791 *outp++ = l>>24;
794 void
795 outvlong(vlong v)
797 int i;
799 for(i = 0; i < 8; i++){
800 *outp++ = v;
801 v >>= 8;
805 void
806 outsend(void)
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;
826 int
827 needoutflush(void)
829 return outmsg >= outdata+DATASIZE;
832 void
833 outflush(void)
835 if(outmsg == outdata)
836 return;
837 outbuffered = 0;
838 /* flow control */
839 outT0(Hack);
840 waitack = 1;
841 do
842 if(rcv() == 0){
843 rescue();
844 exits("eof");
846 while(waitack);
847 outmsg = outdata;
848 outbuffered = 1;