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