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 DEBUG
23 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 void
79 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 void
89 journaln(int out, long n)
90 {
91 char buf[32];
93 sprint(buf, "%ld", n);
94 journal(out, buf);
95 }
96 #else
97 #define journal(a, b)
98 #define journaln(a, b)
99 #endif
101 int
102 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;
112 --nleft;
113 return buf[i++];
116 int
117 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);
154 break;
156 return 0;
159 File *
160 whichfile(int tag)
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;
171 int
172 inmesg(Tmesg type)
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);
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);
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);
278 outTs(Hcheck0, f->tag);
279 moveto(f, f->dot.r);
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 }else
310 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);
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 Strinsert(&genstr, tmpcstr("\\"), l++);
404 Straddc(&genstr, '\0');
405 nextmatch(f, &genstr, p1, 1);
406 moveto(f, sel.p[0]);
407 break;
409 case Tsearch:
410 termlocked++;
411 if(curfile == 0)
412 error(Enofile);
413 if(lastpat.s[0] == 0)
414 panic("Tsearch");
415 nextmatch(curfile, &lastpat, curfile->dot.r.p2, 1);
416 moveto(curfile, sel.p[0]);
417 break;
419 case Tsend:
420 termlocked++;
421 inshort(); /* ignored */
422 p0 = inlong();
423 p1 = inlong();
424 setgenstr(cmd, p0, p1);
425 bufreset(&snarfbuf);
426 bufinsert(&snarfbuf, (Posn)0, genstr.s, genstr.n);
427 outTl(Hsnarflen, genstr.n);
428 if(genstr.s[genstr.n-1] != '\n')
429 Straddc(&genstr, '\n');
430 loginsert(cmd, cmd->b.nc, genstr.s, genstr.n);
431 fileupdate(cmd, FALSE, TRUE);
432 cmd->dot.r.p1 = cmd->dot.r.p2 = cmd->b.nc;
433 telldot(cmd);
434 termcommand();
435 break;
437 case Tdclick:
438 f = whichfile(inshort());
439 p1 = inlong();
440 doubleclick(f, p1);
441 f->tdot.p1 = f->tdot.p2 = p1;
442 telldot(f);
443 outTs(Hunlockfile, f->tag);
444 break;
446 case Tstartsnarf:
447 if (snarfbuf.nc <= 0) { /* nothing to export */
448 outTs(Hsetsnarf, 0);
449 break;
451 c = 0;
452 i = 0;
453 m = snarfbuf.nc;
454 if(m > SNARFSIZE) {
455 m = SNARFSIZE;
456 dprint("?warning: snarf buffer truncated\n");
458 rp = malloc(m*sizeof(Rune));
459 if(rp){
460 bufread(&snarfbuf, 0, rp, m);
461 c = Strtoc(tmprstr(rp, m));
462 free(rp);
463 i = strlen(c);
465 outTs(Hsetsnarf, i);
466 if(c){
467 Write(1, c, i);
468 free(c);
469 } else
470 dprint("snarf buffer too long\n");
471 break;
473 case Tsetsnarf:
474 m = inshort();
475 if(m > SNARFSIZE)
476 error(Etoolong);
477 c = malloc(m+1);
478 if(c){
479 for(i=0; i<m; i++)
480 c[i] = rcvchar();
481 c[m] = 0;
482 str = tmpcstr(c);
483 free(c);
484 bufreset(&snarfbuf);
485 bufinsert(&snarfbuf, (Posn)0, str->s, str->n);
486 freetmpstr(str);
487 outT0(Hunlock);
489 break;
491 case Tack:
492 waitack = 0;
493 break;
495 case Tplumb:
496 f = whichfile(inshort());
497 p0 = inlong();
498 p1 = inlong();
499 pm = emalloc(sizeof(Plumbmsg));
500 pm->src = strdup("sam");
501 pm->dst = 0;
502 /* construct current directory */
503 c = Strtoc(&f->name);
504 if(c[0] == '/')
505 pm->wdir = c;
506 else{
507 wdir = emalloc(1024);
508 getwd(wdir, 1024);
509 pm->wdir = emalloc(1024);
510 snprint(pm->wdir, 1024, "%s/%s", wdir, c);
511 cleanname(pm->wdir);
512 free(wdir);
513 free(c);
515 c = strrchr(pm->wdir, '/');
516 if(c)
517 *c = '\0';
518 pm->type = strdup("text");
519 if(p1 > p0)
520 pm->attr = nil;
521 else{
522 p = p0;
523 while(p0>0 && (i=filereadc(f, p0 - 1))!=' ' && i!='\t' && i!='\n')
524 p0--;
525 while(p1<f->b.nc && (i=filereadc(f, p1))!=' ' && i!='\t' && i!='\n')
526 p1++;
527 sprint(cbuf, "click=%ld", p-p0);
528 pm->attr = plumbunpackattr(cbuf);
530 if(p0==p1 || p1-p0>=BLOCKSIZE){
531 plumbfree(pm);
532 break;
534 setgenstr(f, p0, p1);
535 pm->data = Strtoc(&genstr);
536 pm->ndata = strlen(pm->data);
537 c = plumbpack(pm, &i);
538 if(c != 0){
539 outTs(Hplumb, i);
540 Write(1, c, i);
541 free(c);
543 plumbfree(pm);
544 break;
546 case Texit:
547 exits(0);
549 return TRUE;
552 void
553 snarf(File *f, Posn p1, Posn p2, Buffer *buf, int emptyok)
555 Posn l;
556 int i;
558 if(!emptyok && p1==p2)
559 return;
560 bufreset(buf);
561 /* Stage through genbuf to avoid compaction problems (vestigial) */
562 if(p2 > f->b.nc){
563 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 */
564 p2 = f->b.nc;
566 for(l=p1; l<p2; l+=i){
567 i = p2-l>BLOCKSIZE? BLOCKSIZE : p2-l;
568 bufread(&f->b, l, genbuf, i);
569 bufinsert(buf, buf->nc, tmprstr(genbuf, i)->s, i);
573 int
574 inshort(void)
576 ushort n;
578 n = inp[0] | (inp[1]<<8);
579 inp += 2;
580 return n;
583 long
584 inlong(void)
586 ulong n;
588 n = inp[0] | (inp[1]<<8) | (inp[2]<<16) | (inp[3]<<24);
589 inp += 4;
590 return n;
593 long
594 invlong(void)
596 ulong n;
598 n = (inp[7]<<24) | (inp[6]<<16) | (inp[5]<<8) | inp[4];
599 n = (n<<16) | (inp[3]<<8) | inp[2];
600 n = (n<<16) | (inp[1]<<8) | inp[0];
601 inp += 8;
602 return n;
605 void
606 setgenstr(File *f, Posn p0, Posn p1)
608 if(p0 != p1){
609 if(p1-p0 >= TBLOCKSIZE)
610 error(Etoolong);
611 Strinsure(&genstr, p1-p0);
612 bufread(&f->b, p0, genbuf, p1-p0);
613 memmove(genstr.s, genbuf, RUNESIZE*(p1-p0));
614 genstr.n = p1-p0;
615 }else{
616 if(snarfbuf.nc == 0)
617 error(Eempty);
618 if(snarfbuf.nc > TBLOCKSIZE)
619 error(Etoolong);
620 bufread(&snarfbuf, (Posn)0, genbuf, snarfbuf.nc);
621 Strinsure(&genstr, snarfbuf.nc);
622 memmove(genstr.s, genbuf, RUNESIZE*snarfbuf.nc);
623 genstr.n = snarfbuf.nc;
627 void
628 outT0(Hmesg type)
630 outstart(type);
631 outsend();
634 void
635 outTl(Hmesg type, long l)
637 outstart(type);
638 outlong(l);
639 outsend();
642 void
643 outTs(Hmesg type, int s)
645 outstart(type);
646 journaln(1, s);
647 outshort(s);
648 outsend();
651 void
652 outS(String *s)
654 char *c;
655 int i;
657 c = Strtoc(s);
658 i = strlen(c);
659 outcopy(i, c);
660 if(i > 99)
661 c[99] = 0;
662 journaln(1, i);
663 journal(1, c);
664 free(c);
667 void
668 outTsS(Hmesg type, int s1, String *s)
670 outstart(type);
671 outshort(s1);
672 outS(s);
673 outsend();
676 void
677 outTslS(Hmesg type, int s1, Posn l1, String *s)
679 outstart(type);
680 outshort(s1);
681 journaln(1, s1);
682 outlong(l1);
683 journaln(1, l1);
684 outS(s);
685 outsend();
688 void
689 outTS(Hmesg type, String *s)
691 outstart(type);
692 outS(s);
693 outsend();
696 void
697 outTsllS(Hmesg type, int s1, Posn l1, Posn l2, String *s)
699 outstart(type);
700 outshort(s1);
701 outlong(l1);
702 outlong(l2);
703 journaln(1, l1);
704 journaln(1, l2);
705 outS(s);
706 outsend();
709 void
710 outTsll(Hmesg type, int s, Posn l1, Posn l2)
712 outstart(type);
713 outshort(s);
714 outlong(l1);
715 outlong(l2);
716 journaln(1, l1);
717 journaln(1, l2);
718 outsend();
721 void
722 outTsl(Hmesg type, int s, Posn l)
724 outstart(type);
725 outshort(s);
726 outlong(l);
727 journaln(1, l);
728 outsend();
731 void
732 outTsv(Hmesg type, int s, Posn l)
734 outstart(type);
735 outshort(s);
736 outvlong((void*)l);
737 journaln(1, l);
738 outsend();
741 void
742 outstart(Hmesg type)
744 journal(1, hname[type]);
745 outmsg[0] = type;
746 outp = outmsg+3;
749 void
750 outcopy(int count, void *data)
752 memmove(outp, data, count);
753 outp += count;
756 void
757 outshort(int s)
759 *outp++ = s;
760 *outp++ = s>>8;
763 void
764 outlong(long l)
766 *outp++ = l;
767 *outp++ = l>>8;
768 *outp++ = l>>16;
769 *outp++ = l>>24;
772 void
773 outvlong(void *v)
775 int i;
776 ulong l;
778 l = (ulong) v;
779 for(i = 0; i < 8; i++, l >>= 8)
780 *outp++ = l;
783 void
784 outsend(void)
786 int outcount;
788 outcount = outp-outmsg;
789 outcount -= 3;
790 outmsg[1] = outcount;
791 outmsg[2] = outcount>>8;
792 outmsg = outp;
793 if(!noflush){
794 outcount = outmsg-outdata;
795 if (write(1, (char*) outdata, outcount) != outcount)
796 rescue();
797 outmsg = outdata;
798 return;
800 if(outmsg < outdata+DATASIZE)
801 return;
802 outflush();
805 void
806 outflush(void)
808 if(outmsg == outdata)
809 return;
810 noflush = 0;
811 outT0(Hack);
812 waitack = 1;
813 do
814 if(rcv() == 0){
815 rescue();
816 exits("eof");
818 while(waitack);
819 outmsg = outdata;
820 noflush = 1;