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