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