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 str = tmpcstr("\\");
403 Strinsert(&genstr, str, l++);
404 freetmpstr(str);
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;
454 c = 0;
455 i = 0;
456 m = snarfbuf.nc;
457 if(m > SNARFSIZE) {
458 m = SNARFSIZE;
459 dprint("?warning: snarf buffer truncated\n");
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);
468 outTs(Hsetsnarf, i);
469 if(c){
470 Write(1, c, i);
471 free(c);
472 } else
473 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);
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);
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);
533 if(p0==p1 || p1-p0>=BLOCKSIZE){
534 plumbfree(pm);
535 break;
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);
546 plumbfree(pm);
547 break;
549 case Texit:
550 exits(0);
552 return TRUE;
555 void
556 snarf(File *f, Posn p1, Posn p2, Buffer *buf, int emptyok)
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;
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);
576 int
577 inshort(void)
579 ushort n;
581 n = inp[0] | (inp[1]<<8);
582 inp += 2;
583 return n;
586 long
587 inlong(void)
589 ulong n;
591 n = inp[0] | (inp[1]<<8) | (inp[2]<<16) | (inp[3]<<24);
592 inp += 4;
593 return n;
596 long
597 invlong(void)
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;
608 void
609 setgenstr(File *f, Posn p0, Posn p1)
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;
630 void
631 outT0(Hmesg type)
633 outstart(type);
634 outsend();
637 void
638 outTl(Hmesg type, long l)
640 outstart(type);
641 outlong(l);
642 outsend();
645 void
646 outTs(Hmesg type, int s)
648 outstart(type);
649 journaln(1, s);
650 outshort(s);
651 outsend();
654 void
655 outS(String *s)
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);
670 void
671 outTsS(Hmesg type, int s1, String *s)
673 outstart(type);
674 outshort(s1);
675 outS(s);
676 outsend();
679 void
680 outTslS(Hmesg type, int s1, Posn l1, String *s)
682 outstart(type);
683 outshort(s1);
684 journaln(1, s1);
685 outlong(l1);
686 journaln(1, l1);
687 outS(s);
688 outsend();
691 void
692 outTS(Hmesg type, String *s)
694 outstart(type);
695 outS(s);
696 outsend();
699 void
700 outTsllS(Hmesg type, int s1, Posn l1, Posn l2, String *s)
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();
712 void
713 outTsll(Hmesg type, int s, Posn l1, Posn l2)
715 outstart(type);
716 outshort(s);
717 outlong(l1);
718 outlong(l2);
719 journaln(1, l1);
720 journaln(1, l2);
721 outsend();
724 void
725 outTsl(Hmesg type, int s, Posn l)
727 outstart(type);
728 outshort(s);
729 outlong(l);
730 journaln(1, l);
731 outsend();
734 void
735 outTsv(Hmesg type, int s, Posn l)
737 outstart(type);
738 outshort(s);
739 outvlong((void*)l);
740 journaln(1, l);
741 outsend();
744 void
745 outstart(Hmesg type)
747 journal(1, hname[type]);
748 outmsg[0] = type;
749 outp = outmsg+3;
752 void
753 outcopy(int count, void *data)
755 memmove(outp, data, count);
756 outp += count;
759 void
760 outshort(int s)
762 *outp++ = s;
763 *outp++ = s>>8;
766 void
767 outlong(long l)
769 *outp++ = l;
770 *outp++ = l>>8;
771 *outp++ = l>>16;
772 *outp++ = l>>24;
775 void
776 outvlong(void *v)
778 int i;
779 ulong l;
781 l = (ulong) v;
782 for(i = 0; i < 8; i++, l >>= 8)
783 *outp++ = l;
786 void
787 outsend(void)
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;
803 if(outmsg < outdata+DATASIZE)
804 return;
805 outflush();
808 void
809 outflush(void)
811 if(outmsg == outdata)
812 return;
813 noflush = 0;
814 outT0(Hack);
815 waitack = 1;
816 do
817 if(rcv() == 0){
818 rescue();
819 exits("eof");
821 while(waitack);
822 outmsg = outdata;
823 noflush = 1;