xref: /plan9/sys/src/cmd/samterm/mesg.c (revision 4d44ba9b9ee4246ddbd96c7fcaf0918ab92ab35a)
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <thread.h>
5 #include <cursor.h>
6 #include <mouse.h>
7 #include <keyboard.h>
8 #include <frame.h>
9 #include <plumb.h>
10 #include "flayer.h"
11 #include "samterm.h"
12 
13 #define	HSIZE	3	/* Type + short count */
14 Header	h;
15 uchar	indata[DATASIZE+1];	/* room for NUL */
16 uchar	outdata[DATASIZE];
17 short	outcount;
18 int	hversion;
19 int	exiting;
20 
21 void	inmesg(Hmesg, int);
22 int	inshort(int);
23 long	inlong(int);
24 long	invlong(int);
25 void	hsetdot(int, long, long);
26 void	hmoveto(int, long);
27 void	hsetsnarf(int);
28 void	hplumb(int);
29 void	clrlock(void);
30 int	snarfswap(char*, int, char**);
31 
32 void
33 rcv(void)
34 {
35 	int c;
36 	static state = 0;
37 	static count = 0;
38 	static i = 0;
39 	static int errs = 0;
40 
41 	while((c=rcvchar()) != -1)
42 		switch(state){
43 		case 0:
44 			h.type = c;
45 			state++;
46 			break;
47 
48 		case 1:
49 			h.count0 = c;
50 			state++;
51 			break;
52 
53 		case 2:
54 			h.count1 = c;
55 			count = h.count0|(h.count1<<8);
56 			i = 0;
57 			if(count > DATASIZE){
58 				if(++errs < 5){
59 					dumperrmsg(count, h.type, h.count0, c);
60 					state = 0;
61 					continue;
62 				}
63 				fprint(2, "type %d count %d\n", h.type, count);
64 				panic("count>DATASIZE");
65 			}
66 			if(count == 0)
67 				goto zerocount;
68 			state++;
69 			break;
70 
71 		case 3:
72 			indata[i++] = c;
73 			if(i == count){
74 		zerocount:
75 				indata[i] = 0;
76 				inmesg(h.type, count);
77 				state = count = 0;
78 				continue;
79 			}
80 			break;
81 		}
82 }
83 
84 Text *
85 whichtext(int tg)
86 {
87 	int i;
88 
89 	for(i=0; i<nname; i++)
90 		if(tag[i] == tg)
91 			return text[i];
92 	panic("whichtext");
93 	return 0;
94 }
95 
96 void
97 inmesg(Hmesg type, int count)
98 {
99 	Text *t;
100 	int i, m;
101 	long l;
102 	Flayer *lp;
103 
104 	m = inshort(0);
105 	l = inlong(2);
106 	switch(type){
107 	case -1:
108 		panic("rcv error");
109 	default:
110 		fprint(2, "type %d\n", type);
111 		panic("rcv unknown");
112 
113 	case Hversion:
114 		hversion = m;
115 		break;
116 
117 	case Hbindname:
118 		l = invlong(2);		/* for 64-bit pointers */
119 		if((i=whichmenu(m)) < 0)
120 			break;
121 		/* in case of a race, a bindname may already have occurred */
122 		if((t=whichtext(m)) == 0)
123 			t=(Text *)l;
124 		else	/* let the old one win; clean up the new one */
125 			while(((Text *)l)->nwin>0)
126 				closeup(&((Text *)l)->l[((Text *)l)->front]);
127 		text[i] = t;
128 		text[i]->tag = m;
129 		break;
130 
131 	case Hcurrent:
132 		if(whichmenu(m)<0)
133 			break;
134 		t = whichtext(m);
135 		i = which && ((Text *)which->user1)==&cmd && m!=cmd.tag;
136 		if(t==0 && (t = sweeptext(0, m))==0)
137 			break;
138 		if(t->l[t->front].textfn==0)
139 			panic("Hcurrent");
140 		lp = &t->l[t->front];
141 		if(i){
142 			flupfront(lp);
143 			flborder(lp, 0);
144 			work = lp;
145 		}else
146 			current(lp);
147 		break;
148 
149 	case Hmovname:
150 		if((m=whichmenu(m)) < 0)
151 			break;
152 		t = text[m];
153 		l = tag[m];
154 		i = name[m][0];
155 		text[m] = 0;	/* suppress panic in menudel */
156 		menudel(m);
157 		if(t == &cmd)
158 			m = 0;
159 		else{
160 			if (nname>0 && text[0]==&cmd)
161 				m = 1;
162 			else m = 0;
163 			for(; m<nname; m++)
164 				if(strcmp((char*)indata+2, (char*)name[m]+1)<0)
165 					break;
166 		}
167 		menuins(m, indata+2, t, i, (int)l);
168 		break;
169 
170 	case Hgrow:
171 		if(whichmenu(m) >= 0)
172 			hgrow(m, l, inlong(6), 1);
173 		break;
174 
175 	case Hnewname:
176 		menuins(0, (uchar *)"", (Text *)0, ' ', m);
177 		break;
178 
179 	case Hcheck0:
180 		i = whichmenu(m);
181 		if(i>=0) {
182 			t = text[i];
183 			if(t)
184 				t->lock++;
185 			outTs(Tcheck, m);
186 		}
187 		break;
188 
189 	case Hcheck:
190 		i = whichmenu(m);
191 		if(i>=0) {
192 			t = text[i];
193 			if(t && t->lock)
194 				t->lock--;
195 			hcheck(m);
196 		}
197 		break;
198 
199 	case Hunlock:
200 		clrlock();
201 		break;
202 
203 	case Hdata:
204 		if(whichmenu(m) >= 0)
205 			l += hdata(m, l, indata+6, count-6);
206 	Checkscroll:
207 		if(m == cmd.tag){
208 			for(i=0; i<NL; i++){
209 				lp = &cmd.l[i];
210 				if(lp->textfn)
211 					center(lp, l>=0? l : lp->p1);
212 			}
213 		}
214 		break;
215 
216 	case Horigin:
217 		if(whichmenu(m) >= 0)
218 			horigin(m, l);
219 		break;
220 
221 	case Hunlockfile:
222 		if(whichmenu(m)>=0 && (t = whichtext(m))->lock){
223 			--t->lock;
224 			l = -1;
225 			goto Checkscroll;
226 		}
227 		break;
228 
229 	case Hsetdot:
230 		if(whichmenu(m) >= 0)
231 			hsetdot(m, l, inlong(6));
232 		break;
233 
234 	case Hgrowdata:
235 		if(whichmenu(m)<0)
236 			break;
237 		hgrow(m, l, inlong(6), 0);
238 		whichtext(m)->lock++;	/* fake the request */
239 		l += hdata(m, l, indata+10, count-10);
240 		goto Checkscroll;
241 
242 	case Hmoveto:
243 		if(whichmenu(m)>=0)
244 			hmoveto(m, l);
245 		break;
246 
247 	case Hclean:
248 		if((m = whichmenu(m)) >= 0)
249 			name[m][0] = ' ';
250 		break;
251 
252 	case Hdirty:
253 		if((m = whichmenu(m))>=0)
254 			name[m][0] = '\'';
255 		break;
256 
257 	case Hdelname:
258 		if((m=whichmenu(m)) >= 0)
259 			menudel(m);
260 		break;
261 
262 	case Hcut:
263 		if(whichmenu(m) >= 0)
264 			hcut(m, l, inlong(6));
265 		break;
266 
267 	case Hclose:
268 		if(whichmenu(m)<0 || (t = whichtext(m))==0)
269 			break;
270 		l = t->nwin;
271 		for(i = 0,lp = t->l; l>0 && i<NL; i++,lp++)
272 			if(lp->textfn){
273 				closeup(lp);
274 				--l;
275 			}
276 		break;
277 
278 	case Hsetpat:
279 		setpat((char *)indata);
280 		break;
281 
282 	case Hsetsnarf:
283 		hsetsnarf(m);
284 		break;
285 
286 	case Hsnarflen:
287 		snarflen = inlong(0);
288 		break;
289 
290 	case Hack:
291 		outT0(Tack);
292 		break;
293 
294 	case Hexit:
295 		exiting = 1;
296 		outT0(Texit);
297 		threadexitsall(nil);
298 		break;
299 
300 	case Hplumb:
301 		hplumb(m);
302 		break;
303 	}
304 }
305 
306 void
307 setlock(void)
308 {
309 	hostlock++;
310 	setcursor(mousectl, cursor = &lockarrow);
311 }
312 
313 void
314 clrlock(void)
315 {
316 	hasunlocked = 1;
317 	if(hostlock > 0)
318 		hostlock--;
319 	if(hostlock == 0)
320 		setcursor(mousectl, cursor=(Cursor *)0);
321 }
322 
323 void
324 startfile(Text *t)
325 {
326 	outTsv(Tstartfile, t->tag, t);		/* for 64-bit pointers */
327 	setlock();
328 }
329 
330 void
331 startnewfile(int type, Text *t)
332 {
333 	t->tag = Untagged;
334 	outTv(type, t);				/* for 64-bit pointers */
335 }
336 
337 int
338 inshort(int n)
339 {
340 	return indata[n]|(indata[n+1]<<8);
341 }
342 
343 long
344 inlong(int n)
345 {
346 	return indata[n]|(indata[n+1]<<8)|
347 		((long)indata[n+2]<<16)|((long)indata[n+3]<<24);
348 }
349 
350 long
351 invlong(int n)
352 {
353 	long l;
354 
355 	l = (indata[n+7]<<24) | (indata[n+6]<<16) | (indata[n+5]<<8) | indata[n+4];
356 	l = (l<<16) | (indata[n+3]<<8) | indata[n+2];
357 	l = (l<<16) | (indata[n+1]<<8) | indata[n];
358 	return l;
359 }
360 
361 void
362 outT0(Tmesg type)
363 {
364 	outstart(type);
365 	outsend();
366 }
367 
368 void
369 outTl(Tmesg type, long l)
370 {
371 	outstart(type);
372 	outlong(l);
373 	outsend();
374 }
375 
376 void
377 outTs(Tmesg type, int s)
378 {
379 	outstart(type);
380 	outshort(s);
381 	outsend();
382 }
383 
384 void
385 outTss(Tmesg type, int s1, int s2)
386 {
387 	outstart(type);
388 	outshort(s1);
389 	outshort(s2);
390 	outsend();
391 }
392 
393 void
394 outTsll(Tmesg type, int s1, long l1, long l2)
395 {
396 	outstart(type);
397 	outshort(s1);
398 	outlong(l1);
399 	outlong(l2);
400 	outsend();
401 }
402 
403 void
404 outTsl(Tmesg type, int s1, long l1)
405 {
406 	outstart(type);
407 	outshort(s1);
408 	outlong(l1);
409 	outsend();
410 }
411 
412 void
413 outTsv(Tmesg type, int s1, void *l1)
414 {
415 	outstart(type);
416 	outshort(s1);
417 	outvlong(l1);
418 	outsend();
419 }
420 
421 void
422 outTv(Tmesg type, void *l1)
423 {
424 	outstart(type);
425 	outvlong(l1);
426 	outsend();
427 }
428 
429 void
430 outTslS(Tmesg type, int s1, long l1, Rune *s)
431 {
432 	char buf[DATASIZE*3+1];
433 	char *c;
434 
435 	outstart(type);
436 	outshort(s1);
437 	outlong(l1);
438 	c = buf;
439 	while(*s)
440 		c += runetochar(c, s++);
441 	*c++ = 0;
442 	outcopy(c-buf, (uchar *)buf);
443 	outsend();
444 }
445 
446 void
447 outTsls(Tmesg type, int s1, long l1, int s2)
448 {
449 	outstart(type);
450 	outshort(s1);
451 	outlong(l1);
452 	outshort(s2);
453 	outsend();
454 }
455 
456 void
457 outstart(Tmesg type)
458 {
459 	outdata[0] = type;
460 	outcount = 0;
461 }
462 
463 void
464 outcopy(int count, uchar *data)
465 {
466 	while(count--)
467 		outdata[HSIZE+outcount++] = *data++;
468 }
469 
470 void
471 outshort(int s)
472 {
473 	uchar buf[2];
474 
475 	buf[0]=s;
476 	buf[1]=s>>8;
477 	outcopy(2, buf);
478 }
479 
480 void
481 outlong(long l)
482 {
483 	uchar buf[4];
484 
485 	buf[0]=l;
486 	buf[1]=l>>8;
487 	buf[2]=l>>16;
488 	buf[3]=l>>24;
489 	outcopy(4, buf);
490 }
491 
492 void
493 outvlong(void *v)
494 {
495 	int i;
496 	ulong l;
497 	uchar buf[8];
498 
499 	l = (ulong) v;
500 	for(i = 0; i < sizeof(buf); i++, l >>= 8)
501 		buf[i] = l;
502 
503 	outcopy(8, buf);
504 }
505 
506 void
507 outsend(void)
508 {
509 	if(outcount>DATASIZE-HSIZE)
510 		panic("outcount>sizeof outdata");
511 	outdata[1]=outcount;
512 	outdata[2]=outcount>>8;
513 	if(write(1, (char *)outdata, outcount+HSIZE)!=outcount+HSIZE)
514 		panic("write error");
515 }
516 
517 
518 void
519 hsetdot(int m, long p0, long p1)
520 {
521 	Text *t = whichtext(m);
522 	Flayer *l = &t->l[t->front];
523 
524 	flushtyping(1);
525 	flsetselect(l, p0, p1);
526 }
527 
528 void
529 horigin(int m, long p0)
530 {
531 	Text *t = whichtext(m);
532 	Flayer *l = &t->l[t->front];
533 	long a;
534 	ulong n;
535 	Rune *r;
536 
537 	if(!flprepare(l)){
538 		l->origin = p0;
539 		return;
540 	}
541 	a = p0-l->origin;
542 	if(a>=0 && a<l->f.nchars)
543 		frdelete(&l->f, 0, a);
544 	else if(a<0 && -a<l->f.nchars){
545 		r = rload(&t->rasp, p0, l->origin, &n);
546 		frinsert(&l->f, r, r+n, 0);
547 	}else
548 		frdelete(&l->f, 0, l->f.nchars);
549 	l->origin = p0;
550 	scrdraw(l, t->rasp.nrunes);
551 	if(l->visible==Some)
552 		flrefresh(l, l->entire, 0);
553 	hcheck(m);
554 }
555 
556 void
557 hmoveto(int m, long p0)
558 {
559 	Text *t = whichtext(m);
560 	Flayer *l = &t->l[t->front];
561 
562 	if(p0<l->origin || p0-l->origin>l->f.nchars*9/10)
563 		outTsll(Torigin, m, p0, 2L);
564 }
565 
566 void
567 hcheck(int m)
568 {
569 	Flayer *l;
570 	Text *t;
571 	int reqd = 0, i;
572 	long n, nl, a;
573 	Rune *r;
574 
575 	if(m == Untagged)
576 		return;
577 	t = whichtext(m);
578 	if(t == 0)		/* possible in a half-built window */
579 		return;
580 	for(l = &t->l[0], i = 0; i<NL; i++, l++){
581 		if(l->textfn==0 || !flprepare(l))	/* BUG: don't
582 							   need this if BUG below
583 							   is fixed */
584 			continue;
585 		a = t->l[i].origin;
586 		n = rcontig(&t->rasp, a, a+l->f.nchars, 1);
587 		if(n<l->f.nchars)	/* text missing in middle of screen */
588 			a+=n;
589 		else{			/* text missing at end of screen? */
590         Again:
591 		 	if(l->f.lastlinefull)
592 				goto Checksel;	/* all's well */
593 			a = t->l[i].origin+l->f.nchars;
594 			n = t->rasp.nrunes-a;
595 			if(n==0)
596 				goto Checksel;
597 			if(n>TBLOCKSIZE)
598 				n = TBLOCKSIZE;
599 			n = rcontig(&t->rasp, a, a+n, 1);
600 			if(n>0){
601 				rload(&t->rasp, a, a+n, 0);
602 				nl = l->f.nchars;
603 				r = scratch;
604 				flinsert(l, r, r+n, l->origin+nl);
605 				if(nl == l->f.nchars)	/* made no progress */
606 					goto Checksel;
607 				goto Again;
608 			}
609 		}
610 		if(!reqd){
611 			n = rcontig(&t->rasp, a, a+TBLOCKSIZE, 0);
612 			if(n <= 0)
613 				panic("hcheck request==0");
614 			outTsls(Trequest, m, a, (int)n);
615 			outTs(Tcheck, m);
616 			t->lock++;	/* for the Trequest */
617 			t->lock++;	/* for the Tcheck */
618 			reqd++;
619 		}
620 	    Checksel:
621 		flsetselect(l, l->p0, l->p1);
622 	}
623 }
624 
625 void
626 flnewlyvisible(Flayer *l)
627 {
628 	hcheck(((Text *)l->user1)->tag);
629 }
630 
631 void
632 hsetsnarf(int nc)
633 {
634 	char *s2;
635 	char *s1;
636 	int i;
637 	int n;
638 
639 	setcursor(mousectl, &deadmouse);
640 	s2 = alloc(nc+1);
641 	for(i=0; i<nc; i++)
642 		s2[i] = getch();
643 	s2[nc] = 0;
644 	n = snarfswap(s2, nc, &s1);
645 	if(n >= 0){
646 		if(!s1)
647 			n = 0;
648 		s1 = realloc(s1, n+1);
649 		if (!s1)
650 			panic("realloc");
651 		s1[n] = 0;
652 		snarflen = n;
653 		outTs(Tsetsnarf, n);
654 		if(n>0 && write(1, s1, n)!=n)
655 			panic("snarf write error");
656 		free(s1);
657 	}else
658 		outTs(Tsetsnarf, 0);
659 	free(s2);
660 	setcursor(mousectl, cursor);
661 }
662 
663 void
664 hplumb(int nc)
665 {
666 	int i;
667 	char *s;
668 	Plumbmsg *m;
669 
670 	s = alloc(nc);
671 	for(i=0; i<nc; i++)
672 		s[i] = getch();
673 	if(plumbfd > 0){
674 		m = plumbunpack(s, nc);
675 		if(m != 0)
676 			plumbsend(plumbfd, m);
677 		plumbfree(m);
678 	}
679 	free(s);
680 }
681 
682 void
683 hgrow(int m, long a, long new, int req)
684 {
685 	int i;
686 	Flayer *l;
687 	Text *t = whichtext(m);
688 	long o, b;
689 
690 	if(new <= 0)
691 		panic("hgrow");
692 	rresize(&t->rasp, a, 0L, new);
693 	for(l = &t->l[0], i = 0; i<NL; i++, l++){
694 		if(l->textfn == 0)
695 			continue;
696 		o = l->origin;
697 		b = a-o-rmissing(&t->rasp, o, a);
698 		if(a < o)
699 			l->origin+=new;
700 		if(a < l->p0)
701 			l->p0+=new;
702 		if(a < l->p1)
703 			l->p1+=new;
704 		/* must prevent b temporarily becoming unsigned */
705 		if(!req || a<o || (b>0 && b>l->f.nchars) ||
706 		    (l->f.nchars==0 && a-o>0))
707 			continue;
708 		if(new>TBLOCKSIZE)
709 			new = TBLOCKSIZE;
710 		outTsls(Trequest, m, a, (int)new);
711 		t->lock++;
712 		req = 0;
713 	}
714 }
715 
716 int
717 hdata1(Text *t, long a, Rune *r, int len)
718 {
719 	int i;
720 	Flayer *l;
721 	long o, b;
722 
723 	for(l = &t->l[0], i=0; i<NL; i++, l++){
724 		if(l->textfn==0)
725 			continue;
726 		o = l->origin;
727 		b = a-o-rmissing(&t->rasp, o, a);
728 		/* must prevent b temporarily becoming unsigned */
729 		if(a<o || (b>0 && b>l->f.nchars))
730 			continue;
731 		flinsert(l, r, r+len, o+b);
732 	}
733 	rdata(&t->rasp, a, a+len, r);
734 	rclean(&t->rasp);
735 	return len;
736 }
737 
738 int
739 hdata(int m, long a, uchar *s, int len)
740 {
741 	int i, w;
742 	Text *t = whichtext(m);
743 	Rune buf[DATASIZE], *r;
744 
745 	if(t->lock)
746 		--t->lock;
747 	if(len == 0)
748 		return 0;
749 	r = buf;
750 	for(i=0; i<len; i+=w,s+=w)
751 		w = chartorune(r++, (char*)s);
752 	return hdata1(t, a, buf, r-buf);
753 }
754 
755 int
756 hdatarune(int m, long a, Rune *r, int len)
757 {
758 	Text *t = whichtext(m);
759 
760 	if(t->lock)
761 		--t->lock;
762 	if(len == 0)
763 		return 0;
764 	return hdata1(t, a, r, len);
765 }
766 
767 void
768 hcut(int m, long a, long old)
769 {
770 	Flayer *l;
771 	Text *t = whichtext(m);
772 	int i;
773 	long o, b;
774 
775 	if(t->lock)
776 		--t->lock;
777 	for(l = &t->l[0], i = 0; i<NL; i++, l++){
778 		if(l->textfn == 0)
779 			continue;
780 		o = l->origin;
781 		b = a-o-rmissing(&t->rasp, o, a);
782 		/* must prevent b temporarily becoming unsigned */
783 		if((b<0 || b<l->f.nchars) && a+old>=o){
784 			fldelete(l, b<0? o : o+b,
785 			    a+old-rmissing(&t->rasp, o, a+old));
786 		}
787 		if(a+old<o)
788 			l->origin-=old;
789 		else if(a<=o)
790 			l->origin = a;
791 		if(a+old<l->p0)
792 			l->p0-=old;
793 		else if(a<=l->p0)
794 			l->p0 = a;
795 		if(a+old<l->p1)
796 			l->p1-=old;
797 		else if(a<=l->p1)
798 			l->p1 = a;
799 	}
800 	rresize(&t->rasp, a, old, 0L);
801 	rclean(&t->rasp);
802 }
803