Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <thread.h>
5 #include <mouse.h>
6 #include <cursor.h>
7 #include <keyboard.h>
8 #include <frame.h>
9 #include <plumb.h>
10 #include "flayer.h"
11 #include "samterm.h"
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 hostfd[2];
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**);
32 void
33 rcv(void)
34 {
35 int c;
36 static int state = 0;
37 static int count = 0;
38 static int i = 0;
39 static int errs = 0;
41 while((c=rcvchar()) != -1)
42 switch(state){
43 case 0:
44 h.type = c;
45 state++;
46 break;
48 case 1:
49 h.count0 = c;
50 state++;
51 break;
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;
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 }
84 Text *
85 whichtext(int tg)
86 {
87 int i;
89 for(i=0; i<nname; i++)
90 if(tag[i] == tg)
91 return text[i];
92 panic("whichtext");
93 return 0;
94 }
96 void
97 inmesg(Hmesg type, int count)
98 {
99 Text *t;
100 int i, m;
101 long l;
102 Flayer *lp;
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");
113 case Hversion:
114 hversion = m;
115 break;
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;
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;
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;
167 menuins(m, indata+2, t, i, (int)l);
168 break;
170 case Hgrow:
171 if(whichmenu(m) >= 0)
172 hgrow(m, l, inlong(6), 1);
173 break;
175 case Hnewname:
176 menuins(0, (uchar *)"", (Text *)0, ' ', m);
177 break;
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);
187 break;
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);
197 break;
199 case Hunlock:
200 clrlock();
201 break;
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);
214 break;
216 case Horigin:
217 if(whichmenu(m) >= 0)
218 horigin(m, l);
219 break;
221 case Hunlockfile:
222 if(whichmenu(m)>=0 && (t = whichtext(m))->lock){
223 --t->lock;
224 l = -1;
225 goto Checkscroll;
227 break;
229 case Hsetdot:
230 if(whichmenu(m) >= 0)
231 hsetdot(m, l, inlong(6));
232 break;
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;
242 case Hmoveto:
243 if(whichmenu(m)>=0)
244 hmoveto(m, l);
245 break;
247 case Hclean:
248 if((m = whichmenu(m)) >= 0)
249 name[m][0] = ' ';
250 break;
252 case Hdirty:
253 if((m = whichmenu(m))>=0)
254 name[m][0] = '\'';
255 break;
257 case Hdelname:
258 if((m=whichmenu(m)) >= 0)
259 menudel(m);
260 break;
262 case Hcut:
263 if(whichmenu(m) >= 0)
264 hcut(m, l, inlong(6));
265 break;
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;
276 break;
278 case Hsetpat:
279 setpat((char *)indata);
280 break;
282 case Hsetsnarf:
283 hsetsnarf(m);
284 break;
286 case Hsnarflen:
287 snarflen = inlong(0);
288 break;
290 case Hack:
291 outT0(Tack);
292 break;
294 case Hexit:
295 outT0(Texit);
296 threadexitsall(nil);
297 break;
299 case Hplumb:
300 hplumb(m);
301 break;
305 void
306 setlock(void)
308 hostlock++;
309 setcursor(mousectl, cursor = &lockarrow);
312 void
313 clrlock(void)
315 hasunlocked = 1;
316 if(hostlock > 0)
317 hostlock--;
318 if(hostlock == 0)
319 setcursor(mousectl, cursor=(Cursor *)0);
322 void
323 startfile(Text *t)
325 outTsv(Tstartfile, t->tag, t); /* for 64-bit pointers */
326 setlock();
329 void
330 startnewfile(int type, Text *t)
332 t->tag = Untagged;
333 outTv(type, t); /* for 64-bit pointers */
336 int
337 inshort(int n)
339 return indata[n]|(indata[n+1]<<8);
342 long
343 inlong(int n)
345 return indata[n]|(indata[n+1]<<8)|
346 ((long)indata[n+2]<<16)|((long)indata[n+3]<<24);
349 long
350 invlong(int n)
352 long l;
354 l = (indata[n+7]<<24) | (indata[n+6]<<16) | (indata[n+5]<<8) | indata[n+4];
355 l = (l<<16) | (indata[n+3]<<8) | indata[n+2];
356 l = (l<<16) | (indata[n+1]<<8) | indata[n];
357 return l;
360 void
361 outT0(Tmesg type)
363 outstart(type);
364 outsend();
367 void
368 outTl(Tmesg type, long l)
370 outstart(type);
371 outlong(l);
372 outsend();
375 void
376 outTs(Tmesg type, int s)
378 outstart(type);
379 outshort(s);
380 outsend();
383 void
384 outTss(Tmesg type, int s1, int s2)
386 outstart(type);
387 outshort(s1);
388 outshort(s2);
389 outsend();
392 void
393 outTsll(Tmesg type, int s1, long l1, long l2)
395 outstart(type);
396 outshort(s1);
397 outlong(l1);
398 outlong(l2);
399 outsend();
402 void
403 outTsl(Tmesg type, int s1, long l1)
405 outstart(type);
406 outshort(s1);
407 outlong(l1);
408 outsend();
411 void
412 outTsv(Tmesg type, int s1, void *l1)
414 outstart(type);
415 outshort(s1);
416 outvlong(l1);
417 outsend();
420 void
421 outTv(Tmesg type, void *l1)
423 outstart(type);
424 outvlong(l1);
425 outsend();
428 void
429 outTslS(Tmesg type, int s1, long l1, Rune *s)
431 char buf[DATASIZE*3+1];
432 char *c;
434 outstart(type);
435 outshort(s1);
436 outlong(l1);
437 c = buf;
438 while(*s)
439 c += runetochar(c, s++);
440 *c++ = 0;
441 outcopy(c-buf, (uchar *)buf);
442 outsend();
445 void
446 outTsls(Tmesg type, int s1, long l1, int s2)
448 outstart(type);
449 outshort(s1);
450 outlong(l1);
451 outshort(s2);
452 outsend();
455 void
456 outstart(Tmesg type)
458 outdata[0] = type;
459 outcount = 0;
462 void
463 outcopy(int count, uchar *data)
465 while(count--)
466 outdata[HSIZE+outcount++] = *data++;
469 void
470 outshort(int s)
472 uchar buf[2];
474 buf[0]=s;
475 buf[1]=s>>8;
476 outcopy(2, buf);
479 void
480 outlong(long l)
482 uchar buf[4];
484 buf[0]=l;
485 buf[1]=l>>8;
486 buf[2]=l>>16;
487 buf[3]=l>>24;
488 outcopy(4, buf);
491 void
492 outvlong(void *v)
494 int i;
495 ulong l;
496 uchar buf[8];
498 l = (ulong) v;
499 for(i = 0; i < sizeof(buf); i++, l >>= 8)
500 buf[i] = l;
502 outcopy(8, buf);
505 void
506 outsend(void)
508 if(outcount>DATASIZE-HSIZE)
509 panic("outcount>sizeof outdata");
510 outdata[1]=outcount;
511 outdata[2]=outcount>>8;
512 if(write(hostfd[1], (char *)outdata, outcount+HSIZE)!=outcount+HSIZE)
513 panic("write error");
517 void
518 hsetdot(int m, long p0, long p1)
520 Text *t = whichtext(m);
521 Flayer *l = &t->l[t->front];
523 flushtyping(1);
524 flsetselect(l, p0, p1);
527 void
528 horigin(int m, long p0)
530 Text *t = whichtext(m);
531 Flayer *l = &t->l[t->front];
532 long a;
533 ulong n;
534 Rune *r;
536 if(!flprepare(l)){
537 l->origin = p0;
538 return;
540 a = p0-l->origin;
541 if(a>=0 && a<l->f.nchars)
542 frdelete(&l->f, 0, a);
543 else if(a<0 && -a<l->f.nchars){
544 r = rload(&t->rasp, p0, l->origin, &n);
545 frinsert(&l->f, r, r+n, 0);
546 }else
547 frdelete(&l->f, 0, l->f.nchars);
548 l->origin = p0;
549 scrdraw(l, t->rasp.nrunes);
550 if(l->visible==Some)
551 flrefresh(l, l->entire, 0);
552 hcheck(m);
555 void
556 hmoveto(int m, long p0)
558 Text *t = whichtext(m);
559 Flayer *l = &t->l[t->front];
561 if(p0<l->origin || p0-l->origin>l->f.nchars*9/10)
562 outTsll(Torigin, m, p0, 2L);
565 void
566 hcheck(int m)
568 Flayer *l;
569 Text *t;
570 int reqd = 0, i;
571 long n, nl, a;
572 Rune *r;
574 if(m == Untagged)
575 return;
576 t = whichtext(m);
577 if(t == 0) /* possible in a half-built window */
578 return;
579 for(l = &t->l[0], i = 0; i<NL; i++, l++){
580 if(l->textfn==0 || !flprepare(l)) /* BUG: don't
581 need this if BUG below
582 is fixed */
583 continue;
584 a = t->l[i].origin;
585 n = rcontig(&t->rasp, a, a+l->f.nchars, 1);
586 if(n<l->f.nchars) /* text missing in middle of screen */
587 a+=n;
588 else{ /* text missing at end of screen? */
589 Again:
590 if(l->f.lastlinefull)
591 goto Checksel; /* all's well */
592 a = t->l[i].origin+l->f.nchars;
593 n = t->rasp.nrunes-a;
594 if(n==0)
595 goto Checksel;
596 if(n>TBLOCKSIZE)
597 n = TBLOCKSIZE;
598 n = rcontig(&t->rasp, a, a+n, 1);
599 if(n>0){
600 rload(&t->rasp, a, a+n, 0);
601 nl = l->f.nchars;
602 r = scratch;
603 flinsert(l, r, r+n, l->origin+nl);
604 if(nl == l->f.nchars) /* made no progress */
605 goto Checksel;
606 goto Again;
609 if(!reqd){
610 n = rcontig(&t->rasp, a, a+TBLOCKSIZE, 0);
611 if(n <= 0)
612 panic("hcheck request==0");
613 outTsls(Trequest, m, a, (int)n);
614 outTs(Tcheck, m);
615 t->lock++; /* for the Trequest */
616 t->lock++; /* for the Tcheck */
617 reqd++;
619 Checksel:
620 flsetselect(l, l->p0, l->p1);
624 void
625 flnewlyvisible(Flayer *l)
627 hcheck(((Text *)l->user1)->tag);
630 void
631 hsetsnarf(int nc)
633 char *s2;
634 char *s1;
635 int i;
636 int n;
638 setcursor(mousectl, &deadmouse);
639 s2 = alloc(nc+1);
640 for(i=0; i<nc; i++)
641 s2[i] = getch();
642 s2[nc] = 0;
643 n = snarfswap(s2, nc, &s1);
644 if(n >= 0){
645 if(!s1)
646 n = 0;
647 if(n > 65535){
648 s1 = strdup("<snarf too long>");
649 if (!s1)
650 panic("strdup");
651 n = strlen(s1);
652 }else{
653 s1 = realloc(s1, n+1);
654 if (!s1)
655 panic("realloc");
656 s1[n] = 0;
658 snarflen = n;
659 outTs(Tsetsnarf, n);
660 if(n>0 && write(hostfd[1], s1, n)!=n)
661 panic("snarf write error");
662 free(s1);
663 }else
664 outTs(Tsetsnarf, 0);
665 free(s2);
666 setcursor(mousectl, cursor);
669 void
670 hplumb(int nc)
672 int i;
673 char *s;
674 Plumbmsg *m;
676 s = alloc(nc);
677 for(i=0; i<nc; i++)
678 s[i] = getch();
679 if(plumbfd > 0){
680 m = plumbunpack(s, nc);
681 if(m != 0)
682 plumbsend(plumbfd, m);
683 plumbfree(m);
685 free(s);
688 void
689 hgrow(int m, long a, long new, int req)
691 int i;
692 Flayer *l;
693 Text *t = whichtext(m);
694 long o, b;
696 if(new <= 0)
697 panic("hgrow");
698 rresize(&t->rasp, a, 0L, new);
699 for(l = &t->l[0], i = 0; i<NL; i++, l++){
700 if(l->textfn == 0)
701 continue;
702 o = l->origin;
703 b = a-o-rmissing(&t->rasp, o, a);
704 if(a < o)
705 l->origin+=new;
706 if(a < l->p0)
707 l->p0+=new;
708 if(a < l->p1)
709 l->p1+=new;
710 /* must prevent b temporarily becoming unsigned */
711 if(!req || a<o || (b>0 && b>l->f.nchars) ||
712 (l->f.nchars==0 && a-o>0))
713 continue;
714 if(new>TBLOCKSIZE)
715 new = TBLOCKSIZE;
716 outTsls(Trequest, m, a, (int)new);
717 t->lock++;
718 req = 0;
722 int
723 hdata1(Text *t, long a, Rune *r, int len)
725 int i;
726 Flayer *l;
727 long o, b;
729 for(l = &t->l[0], i=0; i<NL; i++, l++){
730 if(l->textfn==0)
731 continue;
732 o = l->origin;
733 b = a-o-rmissing(&t->rasp, o, a);
734 /* must prevent b temporarily becoming unsigned */
735 if(a<o || (b>0 && b>l->f.nchars))
736 continue;
737 flinsert(l, r, r+len, o+b);
739 rdata(&t->rasp, a, a+len, r);
740 rclean(&t->rasp);
741 return len;
744 int
745 hdata(int m, long a, uchar *s, int len)
747 int i, w;
748 Text *t = whichtext(m);
749 Rune buf[DATASIZE], *r;
751 if(t->lock)
752 --t->lock;
753 if(len == 0)
754 return 0;
755 r = buf;
756 for(i=0; i<len; i+=w,s+=w)
757 w = chartorune(r++, (char*)s);
758 return hdata1(t, a, buf, r-buf);
761 int
762 hdatarune(int m, long a, Rune *r, int len)
764 Text *t = whichtext(m);
766 if(t->lock)
767 --t->lock;
768 if(len == 0)
769 return 0;
770 return hdata1(t, a, r, len);
773 void
774 hcut(int m, long a, long old)
776 Flayer *l;
777 Text *t = whichtext(m);
778 int i;
779 long o, b;
781 if(t->lock)
782 --t->lock;
783 for(l = &t->l[0], i = 0; i<NL; i++, l++){
784 if(l->textfn == 0)
785 continue;
786 o = l->origin;
787 b = a-o-rmissing(&t->rasp, o, a);
788 /* must prevent b temporarily becoming unsigned */
789 if((b<0 || b<l->f.nchars) && a+old>=o){
790 fldelete(l, b<0? o : o+b,
791 a+old-rmissing(&t->rasp, o, a+old));
793 if(a+old<o)
794 l->origin-=old;
795 else if(a<=o)
796 l->origin = a;
797 if(a+old<l->p0)
798 l->p0-=old;
799 else if(a<=l->p0)
800 l->p0 = a;
801 if(a+old<l->p1)
802 l->p1-=old;
803 else if(a<=l->p1)
804 l->p1 = a;
806 rresize(&t->rasp, a, old, 0L);
807 rclean(&t->rasp);