mesg.c - sam - An updated version of the sam text editor. | |
git clone git://vernunftzentrum.de/sam.git | |
Log | |
Files | |
Refs | |
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) | indat… | |
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 … | |
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 } |