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