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