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