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