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 DEBUG
30 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 void
86 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 void
96 journaln(int out, long n)
97 {
98 char buf[32];
100 snprint(buf, sizeof buf, "%ld", n);
101 journal(out, buf);
104 void
105 journalv(int out, vlong v)
107 char buf[32];
109 snprint(buf, sizeof buf, "%lld", v);
110 journal(out, buf);
113 #else
114 #define journal(a, b)
115 #define journaln(a, b)
116 #endif
118 int
119 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;
129 --nleft;
130 return buf[i++];
133 int
134 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);
171 break;
173 return 0;
176 File *
177 whichfile(int tag)
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;
188 int
189 inmesg(Tmesg type)
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);
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);
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);
296 outTs(Hcheck0, f->tag);
297 moveto(f, f->dot.r);
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 }else
328 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);
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);
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;
472 c = 0;
473 i = 0;
474 m = snarfbuf.nc;
475 if(m > SNARFSIZE) {
476 m = SNARFSIZE;
477 dprint("?warning: snarf buffer truncated\n");
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);
486 outTs(Hsetsnarf, i);
487 if(c){
488 Write(1, c, i);
489 free(c);
490 } else
491 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);
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);
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);
551 if(p0==p1 || p1-p0>=BLOCKSIZE){
552 plumbfree(pm);
553 break;
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);
564 plumbfree(pm);
565 break;
567 case Texit:
568 exits(0);
570 return TRUE;
573 void
574 snarf(File *f, Posn p1, Posn p2, Buffer *buf, int emptyok)
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;
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);
594 int
595 inshort(void)
597 ushort n;
599 n = inp[0] | (inp[1]<<8);
600 inp += 2;
601 return n;
604 long
605 inlong(void)
607 ulong n;
609 n = inp[0] | (inp[1]<<8) | (inp[2]<<16) | (inp[3]<<24);
610 inp += 4;
611 return n;
614 vlong
615 invlong(void)
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;
626 void
627 setgenstr(File *f, Posn p0, Posn p1)
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;
648 void
649 outT0(Hmesg type)
651 outstart(type);
652 outsend();
655 void
656 outTl(Hmesg type, long l)
658 outstart(type);
659 outlong(l);
660 outsend();
663 void
664 outTs(Hmesg type, int s)
666 outstart(type);
667 journaln(1, s);
668 outshort(s);
669 outsend();
672 void
673 outS(String *s)
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);
688 void
689 outTsS(Hmesg type, int s1, String *s)
691 outstart(type);
692 outshort(s1);
693 outS(s);
694 outsend();
697 void
698 outTslS(Hmesg type, int s1, Posn l1, String *s)
700 outstart(type);
701 outshort(s1);
702 journaln(1, s1);
703 outlong(l1);
704 journaln(1, l1);
705 outS(s);
706 outsend();
709 void
710 outTS(Hmesg type, String *s)
712 outstart(type);
713 outS(s);
714 outsend();
717 void
718 outTsllS(Hmesg type, int s1, Posn l1, Posn l2, String *s)
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();
730 void
731 outTsll(Hmesg type, int s, Posn l1, Posn l2)
733 outstart(type);
734 outshort(s);
735 outlong(l1);
736 outlong(l2);
737 journaln(1, l1);
738 journaln(1, l2);
739 outsend();
742 void
743 outTsl(Hmesg type, int s, Posn l)
745 outstart(type);
746 outshort(s);
747 outlong(l);
748 journaln(1, l);
749 outsend();
752 void
753 outTsv(Hmesg type, int s, vlong v)
755 outstart(type);
756 outshort(s);
757 outvlong(v);
758 journaln(1, v);
759 outsend();
762 void
763 outstart(Hmesg type)
765 journal(1, hname[type]);
766 outmsg[0] = type;
767 outp = outmsg+3;
770 void
771 outcopy(int count, void *data)
773 memmove(outp, data, count);
774 outp += count;
777 void
778 outshort(int s)
780 *outp++ = s;
781 *outp++ = s>>8;
784 void
785 outlong(long l)
787 *outp++ = l;
788 *outp++ = l>>8;
789 *outp++ = l>>16;
790 *outp++ = l>>24;
793 void
794 outvlong(vlong v)
796 int i;
798 for(i = 0; i < 8; i++){
799 *outp++ = v;
800 v >>= 8;
804 void
805 outsend(void)
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;
825 int
826 needoutflush(void)
828 return outmsg >= outdata+DATASIZE;
831 void
832 outflush(void)
834 if(outmsg == outdata)
835 return;
836 outbuffered = 0;
837 /* flow control */
838 outT0(Hack);
839 waitack = 1;
840 do
841 if(rcv() == 0){
842 rescue();
843 exits("eof");
845 while(waitack);
846 outmsg = outdata;
847 outbuffered = 1;