xref: /plan9-contrib/sys/src/cmd/sam/mesg.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include "sam.h"
2 
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;
15 
16 long	inlong(void);
17 long	invlong(void);
18 int	inshort(void);
19 int	inmesg(Tmesg);
20 void	setgenstr(File*, Posn, Posn);
21 
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 };
50 
51 char *tname[] = {
52 	[Tversion]	"Tversion",
53 	[Tstartcmdfile]	"Tstartcmdfile",
54 	[Tcheck]	"Tcheck",
55 	[Trequest]	"Trequest",
56 	[Torigin]	"Torigin",
57 	[Tstartfile]	"Tstartfile",
58 	[Tworkfile]	"Tworkfile",
59 	[Ttype]		"Ttype",
60 	[Tcut]		"Tcut",
61 	[Tpaste]	"Tpaste",
62 	[Tsnarf]	"Tsnarf",
63 	[Tstartnewfile]	"Tstartnewfile",
64 	[Twrite]	"Twrite",
65 	[Tclose]	"Tclose",
66 	[Tlook]		"Tlook",
67 	[Tsearch]	"Tsearch",
68 	[Tsend]		"Tsend",
69 	[Tdclick]	"Tdclick",
70 	[Tstartsnarf]	"Tstartsnarf",
71 	[Tsetsnarf]	"Tsetsnarf",
72 	[Tack]		"Tack",
73 	[Texit]		"Texit",
74 };
75 
76 void
77 journal(int out, char *s)
78 {
79 	static int fd = 0;
80 
81 	if(fd <= 0)
82 		fd = create("/tmp/sam.out", 1, 0666L);
83 	fprint(fd, "%s%s\n", out? "out: " : "in:  ", s);
84 }
85 
86 void
87 journaln(int out, long n)
88 {
89 	char buf[32];
90 	sprint(buf, "%d", n);
91 	journal(out, buf);
92 }
93 #else
94 #define	journal(a, b)
95 #define journaln(a, b)
96 #endif
97 
98 int
99 rcvchar(void){
100 	static uchar buf[64];
101 	static i, nleft = 0;
102 
103 	if(nleft <= 0){
104 		nleft = read(0, (char *)buf, sizeof buf);
105 		if(nleft <= 0)
106 			return -1;
107 		i = 0;
108 	}
109 	--nleft;
110 	return buf[i++];
111 }
112 
113 int
114 rcv(void){
115 	int c;
116 	static state = 0;
117 	static count = 0;
118 	static i = 0;
119 
120 	while((c=rcvchar()) != -1)
121 		switch(state){
122 		case 0:
123 			h.type = c;
124 			state++;
125 			break;
126 
127 		case 1:
128 			h.count0 = c;
129 			state++;
130 			break;
131 
132 		case 2:
133 			h.count1 = c;
134 			count = h.count0|(h.count1<<8);
135 			i = 0;
136 			if(count > DATASIZE)
137 				panic("count>DATASIZE");
138 			if(count == 0)
139 				goto zerocount;
140 			state++;
141 			break;
142 
143 		case 3:
144 			indata[i++] = c;
145 			if(i == count){
146 		zerocount:
147 				indata[i] = 0;
148 				state = count = 0;
149 				return inmesg(h.type);
150 			}
151 			break;
152 		}
153 	return 0;
154 }
155 
156 File *
157 whichfile(int tag)
158 {
159 	int i;
160 
161 	for(i = 0; i<file.nused; i++)
162 		if(file.filepptr[i]->tag==tag)
163 			return file.filepptr[i];
164 	hiccough((char *)0);
165 	return 0;
166 }
167 
168 int
169 inmesg(Tmesg type)
170 {
171 	Rune buf[1025];
172 	int i, m;
173 	short s;
174 	long l, l1;
175 	File *f;
176 	Posn p0, p1;
177 	Range r;
178 	String *str;
179 	char *c;
180 	Rune *rp;
181 
182 	if(type > TMAX)
183 		panic("inmesg");
184 
185 	journal(0, tname[type]);
186 
187 	inp = indata;
188 	switch(type){
189 	case -1:
190 		panic("rcv error");
191 
192 	default:
193 		fprint(2, "unknown type %d\n", type);
194 		panic("rcv unknown");
195 
196 	case Tversion:
197 		tversion = inshort();
198 		journaln(0, tversion);
199 		break;
200 
201 	case Tstartcmdfile:
202 		l = invlong();		/* for 64-bit pointers */
203 		journaln(0, l);
204 		Strdupl(&genstr, samname);
205 		cmd = newfile();
206 		outTsv(Hbindname, cmd->tag, l);
207 		outTs(Hcurrent, cmd->tag);
208 		Fsetname(cmd, &genstr);
209 		cmd->rasp = emalloc(sizeof(List));
210 		cmd->state = Clean;
211 		if(cmdstr.n){
212 			Finsert(cmd, &cmdstr, 0L);
213 			Strdelete(&cmdstr, 0L, (Posn)cmdstr.n);
214 		}
215 		Fupdate(cmd, FALSE, TRUE);
216 		outT0(Hunlock);
217 		break;
218 
219 	case Tcheck:
220 		/* go through whichfile to check the tag */
221 		outTs(Hcheck, whichfile(inshort())->tag);
222 		break;
223 
224 	case Trequest:
225 		f = whichfile(inshort());
226 		p0 = inlong();
227 		p1 = p0+inshort();
228 		journaln(0, p0);
229 		journaln(0, p1-p0);
230 		if(f->state == Unread)
231 			panic("Trequest: unread");
232 		if(p1>f->nrunes)
233 			p1 = f->nrunes;
234 		if(p0>f->nrunes) /* can happen e.g. scrolling during command */
235 			p0 = f->nrunes;
236 		if(p0 == p1){
237 			i = 0;
238 			r.p1 = r.p2 = p0;
239 		}else{
240 			r = rdata(f->rasp, p0, p1-p0);
241 			i = r.p2-r.p1;
242 			if(Fchars(f, buf, r.p1, r.p2)!=i)
243 				panic("Trequest 2");
244 		}
245 		buf[i]=0;
246 		outTslS(Hdata, f->tag, r.p1, tmprstr(buf, i+1));
247 		break;
248 
249 	case Torigin:
250 		s = inshort();
251 		l = inlong();
252 		l1 = inlong();
253 		journaln(0, l1);
254 		lookorigin(whichfile(s), l, l1);
255 		break;
256 
257 	case Tstartfile:
258 		f = whichfile(inshort());
259 		if(!f->rasp)	/* this might be a duplicate message */
260 			f->rasp = emalloc(sizeof(List));
261 		current(f);
262 		outTsv(Hbindname, f->tag, invlong());	/* for 64-bit pointers */
263 		outTs(Hcurrent, f->tag);
264 		journaln(0, f->tag);
265 		termlocked++;
266 		if(f->state == Unread)
267 			load(f);
268 		else{
269 			if(f->nrunes>0){
270 				rgrow(f->rasp, 0L, f->nrunes);
271 				outTsll(Hgrow, f->tag, 0L, f->nrunes);
272 			}
273 			outTs(Hcheck0, f->tag);
274 			moveto(f, f->dot.r);
275 		}
276 		break;
277 
278 	case Tworkfile:
279 		i = inshort();
280 		f = whichfile(i);
281 		current(f);
282 		f->dot.r.p1 = inlong();
283 		f->dot.r.p2 = inlong();
284 		f->tdot = f->dot.r;
285 		journaln(0, i);
286 		journaln(0, f->dot.r.p1);
287 		journaln(0, f->dot.r.p2);
288 		break;
289 
290 	case Ttype:
291 		f = whichfile(inshort());
292 		p0 = inlong();
293 		journaln(0, p0);
294 		journal(0, (char*)inp);
295 		str = tmpcstr((char*)inp);
296 		i = str->n;
297 		Finsert(f, str, p0);
298 		if(Fupdate(f, FALSE, FALSE))
299 			modnum++;
300 		if(f==cmd && p0==f->nrunes-i && i>0 && str->s[i-1]=='\n'){
301 			freetmpstr(str);
302 			termlocked++;
303 			termcommand();
304 		}else
305 			freetmpstr(str);
306 		f->dot.r.p1 = f->dot.r.p2 = p0+i; /* terminal knows this already */
307 		f->tdot = f->dot.r;
308 		break;
309 
310 	case Tcut:
311 		f = whichfile(inshort());
312 		p0 = inlong();
313 		p1 = inlong();
314 		journaln(0, p0);
315 		journaln(0, p1);
316 		Fdelete(f, p0, p1);
317 		if(Fupdate(f, FALSE, FALSE))
318 			modnum++;
319 		f->dot.r.p1 = f->dot.r.p2 = p0;
320 		f->tdot = f->dot.r;   /* terminal knows the value of dot already */
321 		break;
322 
323 	case Tpaste:
324 		f = whichfile(inshort());
325 		p0 = inlong();
326 		journaln(0, p0);
327 		for(l=0; l<snarfbuf->nrunes; l+=m){
328 			m = snarfbuf->nrunes-l;
329 			if(m>BLOCKSIZE)
330 				m = BLOCKSIZE;
331 			Bread(snarfbuf, genbuf, m, l);
332 			Finsert(f, tmprstr(genbuf, m), p0);
333 		}
334 		if(Fupdate(f, FALSE, TRUE))
335 			modnum++;
336 		f->dot.r.p1 = p0;
337 		f->dot.r.p2 = p0+snarfbuf->nrunes;
338 		f->tdot.p1 = -1; /* force telldot to tell (arguably a BUG) */
339 		telldot(f);
340 		outTs(Hunlockfile, f->tag);
341 		break;
342 
343 	case Tsnarf:
344 		i = inshort();
345 		p0 = inlong();
346 		p1 = inlong();
347 		snarf(whichfile(i), p0, p1, snarfbuf, 0);
348 		break;
349 
350 	case Tstartnewfile:
351 		l = invlong();
352 		Strdupl(&genstr, empty);
353 		f = newfile();
354 		f->rasp = emalloc(sizeof(List));
355 		outTsv(Hbindname, f->tag, l);
356 		Fsetname(f, &genstr);
357 		outTs(Hcurrent, f->tag);
358 		current(f);
359 		load(f);
360 		break;
361 
362 	case Twrite:
363 		termlocked++;
364 		i = inshort();
365 		journaln(0, i);
366 		f = whichfile(i);
367 		addr.r.p1 = 0;
368 		addr.r.p2 = f->nrunes;
369 		if(f->name.s[0] == 0)
370 			error(Enoname);
371 		Strduplstr(&genstr, &f->name);
372 		writef(f);
373 		break;
374 
375 	case Tclose:
376 		termlocked++;
377 		i = inshort();
378 		journaln(0, i);
379 		f = whichfile(i);
380 		current(f);
381 		trytoclose(f);
382 		/* if trytoclose fails, will error out */
383 		delete(f);
384 		break;
385 
386 	case Tlook:
387 		f = whichfile(inshort());
388 		termlocked++;
389 		p0 = inlong();
390 		p1 = inlong();
391 		journaln(0, p0);
392 		journaln(0, p1);
393 		setgenstr(f, p0, p1);
394 		for(l = 0; l<genstr.n; l++){
395 			i = genstr.s[l];
396 			if(utfrune(".*+?(|)\\[]^$", i))
397 				Strinsert(&genstr, tmpcstr("\\"), l++);
398 		}
399 		Straddc(&genstr, '\0');
400 		nextmatch(f, &genstr, p1, 1);
401 		moveto(f, sel.p[0]);
402 		break;
403 
404 	case Tsearch:
405 		termlocked++;
406 		if(curfile == 0)
407 			error(Enofile);
408 		if(lastpat.s[0] == 0)
409 			panic("Tsearch");
410 		nextmatch(curfile, &lastpat, curfile->dot.r.p2, 1);
411 		moveto(curfile, sel.p[0]);
412 		break;
413 
414 	case Tsend:
415 		termlocked++;
416 		inshort();	/* ignored */
417 		p0 = inlong();
418 		p1 = inlong();
419 		setgenstr(cmd, p0, p1);
420 		Bdelete(snarfbuf, (Posn)0, snarfbuf->nrunes);
421 		Binsert(snarfbuf, &genstr, (Posn)0);
422 		outTl(Hsnarflen, genstr.n);
423 		if(genstr.s[genstr.n-1] != '\n')
424 			Straddc(&genstr, '\n');
425 		Finsert(cmd, &genstr, cmd->nrunes);
426 		Fupdate(cmd, FALSE, TRUE);
427 		cmd->dot.r.p1 = cmd->dot.r.p2 = cmd->nrunes;
428 		telldot(cmd);
429 		termcommand();
430 		break;
431 
432 	case Tdclick:
433 		f = whichfile(inshort());
434 		p1 = inlong();
435 		doubleclick(f, p1);
436 		f->tdot.p1 = f->tdot.p2 = p1;
437 		telldot(f);
438 		outTs(Hunlockfile, f->tag);
439 		break;
440 
441 	case Tstartsnarf:
442 		if (snarfbuf->nrunes <= 0) {	/* nothing to export */
443 			outTs(Hsetsnarf, 0);
444 			break;
445 		}
446 		c = 0;
447 		i = 0;
448 		rp = malloc((snarfbuf->nrunes)*sizeof(Rune));
449 		if(rp){
450 			Bread(snarfbuf, rp, snarfbuf->nrunes, 0);
451 			c = Strtoc(tmprstr(rp, snarfbuf->nrunes));
452 			free(rp);
453 			i = strlen(c);
454 		}
455 		outTs(Hsetsnarf, i);
456 		if(c){
457 			Write(1, c, i);
458 			free(c);
459 		} else
460 			dprint("snarf buffer too long\n");
461 		break;
462 
463 	case Tsetsnarf:
464 		m = inshort();
465 		if(m > SNARFSIZE)
466 			error(Etoolong);
467 		c = malloc(m+1);
468 		if(c){
469 			for(i=0; i<m; i++)
470 				c[i] = rcvchar();
471 			c[m] = 0;
472 			str = tmpcstr(c);
473 			free(c);
474 			Bdelete(snarfbuf, (Posn)0, snarfbuf->nrunes);
475 			Binsert(snarfbuf, str, (Posn)0);
476 			freetmpstr(str);
477 			outT0(Hunlock);
478 		}
479 		break;
480 
481 	case Tack:
482 		waitack = 0;
483 		break;
484 
485 	case Texit:
486 		exits(0);
487 	}
488 	return TRUE;
489 }
490 
491 void
492 snarf(File *f, Posn p1, Posn p2, Buffer *buf, int emptyok)
493 {
494 	Posn l;
495 	int i;
496 
497 	if(!emptyok && p1==p2)
498 		return;
499 	Bdelete(buf, (Posn)0, buf->nrunes);
500 	/* Stage through genbuf to avoid compaction problems (vestigial) */
501 	for(l=p1; l<p2; l+=i){
502 		i = p2-l>BLOCKSIZE? BLOCKSIZE : p2-l;
503 		Fchars(f, genbuf, l, l+i);
504 		Binsert(buf, tmprstr(genbuf, i), buf->nrunes);
505 	}
506 }
507 
508 int
509 inshort(void)
510 {
511 	ushort n;
512 
513 	n = inp[0] | (inp[1]<<8);
514 	inp += 2;
515 	return n;
516 }
517 
518 long
519 inlong(void)
520 {
521 	ulong n;
522 
523 	n = inp[0] | (inp[1]<<8) | (inp[2]<<16) | (inp[3]<<24);
524 	inp += 4;
525 	return n;
526 }
527 
528 long
529 invlong(void)
530 {
531 	ulong n;
532 
533 	n = (inp[7]<<24) | (inp[6]<<16) | (inp[5]<<8) | inp[4];
534 	n = (n<<16) | (inp[3]<<8) | inp[2];
535 	n = (n<<16) | (inp[1]<<8) | inp[0];
536 	inp += 8;
537 	return n;
538 }
539 
540 void
541 setgenstr(File *f, Posn p0, Posn p1)
542 {
543 	if(p0 != p1){
544 		if(p1-p0 >= TBLOCKSIZE)
545 			error(Etoolong);
546 		Strinsure(&genstr, p1-p0);
547 		Fchars(f, genbuf, p0, p1);
548 		memmove(genstr.s, genbuf, RUNESIZE*(p1-p0));
549 		genstr.n = p1-p0;
550 	}else{
551 		if(snarfbuf->nrunes == 0)
552 			error(Eempty);
553 		if(snarfbuf->nrunes > TBLOCKSIZE)
554 			error(Etoolong);
555 		Bread(snarfbuf, genbuf, snarfbuf->nrunes, (Posn)0);
556 		Strinsure(&genstr, snarfbuf->nrunes);
557 		memmove(genstr.s, genbuf, RUNESIZE*snarfbuf->nrunes);
558 		genstr.n = snarfbuf->nrunes;
559 	}
560 }
561 
562 void
563 outT0(Hmesg type)
564 {
565 	outstart(type);
566 	outsend();
567 }
568 
569 void
570 outTl(Hmesg type, long l)
571 {
572 	outstart(type);
573 	outlong(l);
574 	outsend();
575 }
576 
577 void
578 outTs(Hmesg type, int s)
579 {
580 	outstart(type);
581 	journaln(1, s);
582 	outshort(s);
583 	outsend();
584 }
585 
586 void
587 outS(String *s)
588 {
589 	char *c;
590 	int i;
591 
592 	c = Strtoc(s);
593 	i = strlen(c);
594 	outcopy(i, c);
595 	if(i > 99)
596 		c[99] = 0;
597 	journaln(1, i);
598 	journal(1, c);
599 	free(c);
600 }
601 
602 void
603 outTsS(Hmesg type, int s1, String *s)
604 {
605 	outstart(type);
606 	outshort(s1);
607 	outS(s);
608 	outsend();
609 }
610 
611 void
612 outTslS(Hmesg type, int s1, Posn l1, String *s)
613 {
614 	outstart(type);
615 	outshort(s1);
616 	journaln(1, s1);
617 	outlong(l1);
618 	journaln(1, l1);
619 	outS(s);
620 	outsend();
621 }
622 
623 void
624 outTS(Hmesg type, String *s)
625 {
626 	outstart(type);
627 	outS(s);
628 	outsend();
629 }
630 
631 void
632 outTsllS(Hmesg type, int s1, Posn l1, Posn l2, String *s)
633 {
634 	outstart(type);
635 	outshort(s1);
636 	outlong(l1);
637 	outlong(l2);
638 	journaln(1, l1);
639 	journaln(1, l2);
640 	outS(s);
641 	outsend();
642 }
643 
644 void
645 outTsll(Hmesg type, int s, Posn l1, Posn l2)
646 {
647 	outstart(type);
648 	outshort(s);
649 	outlong(l1);
650 	outlong(l2);
651 	journaln(1, l1);
652 	journaln(1, l2);
653 	outsend();
654 }
655 
656 void
657 outTsl(Hmesg type, int s, Posn l)
658 {
659 	outstart(type);
660 	outshort(s);
661 	outlong(l);
662 	journaln(1, l);
663 	outsend();
664 }
665 
666 void
667 outTsv(Hmesg type, int s, Posn l)
668 {
669 	outstart(type);
670 	outshort(s);
671 	outvlong((void*)l);
672 	journaln(1, l);
673 	outsend();
674 }
675 
676 void
677 outstart(Hmesg type)
678 {
679 	journal(1, hname[type]);
680 	outmsg[0] = type;
681 	outp = outmsg+3;
682 }
683 
684 void
685 outcopy(int count, void *data)
686 {
687 	memmove(outp, data, count);
688 	outp += count;
689 }
690 
691 void
692 outshort(int s)
693 {
694 	*outp++ = s;
695 	*outp++ = s>>8;
696 }
697 
698 void
699 outlong(long l)
700 {
701 	*outp++ = l;
702 	*outp++ = l>>8;
703 	*outp++ = l>>16;
704 	*outp++ = l>>24;
705 }
706 
707 void
708 outvlong(void *v)
709 {
710 	int i;
711 	ulong l;
712 
713 	l = (ulong) v;
714 	for(i = 0; i < 8; i++, l >>= 8)
715 		*outp++ = l;
716 }
717 
718 void
719 outsend(void)
720 {
721 	int outcount;
722 
723 	outcount = outp-outmsg;
724 	outcount -= 3;
725 	outmsg[1] = outcount;
726 	outmsg[2] = outcount>>8;
727 	outmsg = outp;
728 	if(!noflush){
729 		outcount = outmsg-outdata;
730 		if (write(1, (char*) outdata, outcount) != outcount)
731 			rescue();
732 		outmsg = outdata;
733 		return;
734 	}
735 	if(outmsg < outdata+DATASIZE)
736 		return;
737 	outflush();
738 }
739 
740 void
741 outflush(void)
742 {
743 	if(outmsg == outdata)
744 		return;
745 	noflush = 0;
746 	outT0(Hack);
747 	waitack = 1;
748 	do
749 		if(rcv() == 0){
750 			rescue();
751 			exits("eof");
752 		}
753 	while(waitack);
754 	outmsg = outdata;
755 	noflush = 1;
756 }
757