Introduction
Introduction Statistics Contact Development Disclaimer Help
mesg.c - 9base - revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log
Files
Refs
README
LICENSE
---
mesg.c (14442B)
---
1 #include "sam.h"
2 Header h;
3 uchar indata[DATASIZE];
4 uchar outdata[2*DATASIZE+3]; /* room for overflow message …
5 uchar *inp;
6 uchar *outp;
7 uchar *outmsg = outdata;
8 Posn cmdpt;
9 Posn cmdptadv;
10 Buffer snarfbuf;
11 int waitack;
12 int outbuffered;
13 int tversion;
14
15 int inshort(void);
16 long inlong(void);
17 vlong invlong(void);
18 int inmesg(Tmesg);
19
20 void outshort(int);
21 void outlong(long);
22 void outvlong(vlong);
23 void outcopy(int, void*);
24 void outsend(void);
25 void outstart(Hmesg);
26
27 void setgenstr(File*, Posn, Posn);
28
29 #ifdef DEBUG
30 char *hname[] = {
31 [Hversion] "Hversion",
32 [Hbindname] "Hbindname",
33 [Hcurrent] "Hcurrent",
34 [Hnewname] "Hnewname",
35 [Hmovname] "Hmovname",
36 [Hgrow] "Hgrow",
37 [Hcheck0] "Hcheck0",
38 [Hcheck] "Hcheck",
39 [Hunlock] "Hunlock",
40 [Hdata] "Hdata",
41 [Horigin] "Horigin",
42 [Hunlockfile] "Hunlockfile",
43 [Hsetdot] "Hsetdot",
44 [Hgrowdata] "Hgrowdata",
45 [Hmoveto] "Hmoveto",
46 [Hclean] "Hclean",
47 [Hdirty] "Hdirty",
48 [Hcut] "Hcut",
49 [Hsetpat] "Hsetpat",
50 [Hdelname] "Hdelname",
51 [Hclose] "Hclose",
52 [Hsetsnarf] "Hsetsnarf",
53 [Hsnarflen] "Hsnarflen",
54 [Hack] "Hack",
55 [Hexit] "Hexit",
56 // [Hplumb] "Hplumb"
57 };
58
59 char *tname[] = {
60 [Tversion] "Tversion",
61 [Tstartcmdfile] "Tstartcmdfile",
62 [Tcheck] "Tcheck",
63 [Trequest] "Trequest",
64 [Torigin] "Torigin",
65 [Tstartfile] "Tstartfile",
66 [Tworkfile] "Tworkfile",
67 [Ttype] "Ttype",
68 [Tcut] "Tcut",
69 [Tpaste] "Tpaste",
70 [Tsnarf] "Tsnarf",
71 [Tstartnewfile] "Tstartnewfile",
72 [Twrite] "Twrite",
73 [Tclose] "Tclose",
74 [Tlook] "Tlook",
75 [Tsearch] "Tsearch",
76 [Tsend] "Tsend",
77 [Tdclick] "Tdclick",
78 [Tstartsnarf] "Tstartsnarf",
79 [Tsetsnarf] "Tsetsnarf",
80 [Tack] "Tack",
81 [Texit] "Texit",
82 // [Tplumb] "Tplumb"
83 };
84
85 void
86 journal(int out, char *s)
87 {
88 static int fd = 0;
89
90 if(fd <= 0)
91 fd = create("/tmp/sam.out", 1, 0666L);
92 fprint(fd, "%s%s\n", out? "out: " : "in: ", s);
93 }
94
95 void
96 journaln(int out, long n)
97 {
98 char buf[32];
99
100 snprint(buf, sizeof buf, "%ld", n);
101 journal(out, buf);
102 }
103
104 void
105 journalv(int out, vlong v)
106 {
107 char buf[32];
108
109 snprint(buf, sizeof buf, "%lld", v);
110 journal(out, buf);
111 }
112
113 #else
114 #define journal(a, b)
115 #define journaln(a, b)
116 #endif
117
118 int
119 rcvchar(void){
120 static uchar buf[64];
121 static int i, nleft = 0;
122
123 if(nleft <= 0){
124 nleft = read(0, (char *)buf, sizeof buf);
125 if(nleft <= 0)
126 return -1;
127 i = 0;
128 }
129 --nleft;
130 return buf[i++];
131 }
132
133 int
134 rcv(void){
135 int c;
136 static int state = 0;
137 static int count = 0;
138 static int i = 0;
139
140 while((c=rcvchar()) != -1)
141 switch(state){
142 case 0:
143 h.type = c;
144 state++;
145 break;
146
147 case 1:
148 h.count0 = c;
149 state++;
150 break;
151
152 case 2:
153 h.count1 = c;
154 count = h.count0|(h.count1<<8);
155 i = 0;
156 if(count > DATASIZE)
157 panic("count>DATASIZE");
158 if(count == 0)
159 goto zerocount;
160 state++;
161 break;
162
163 case 3:
164 indata[i++] = c;
165 if(i == count){
166 zerocount:
167 indata[i] = 0;
168 state = count = 0;
169 return inmesg(h.type);
170 }
171 break;
172 }
173 return 0;
174 }
175
176 File *
177 whichfile(int tag)
178 {
179 int i;
180
181 for(i = 0; i<file.nused; i++)
182 if(file.filepptr[i]->tag==tag)
183 return file.filepptr[i];
184 hiccough((char *)0);
185 return 0;
186 }
187
188 int
189 inmesg(Tmesg type)
190 {
191 Rune buf[1025];
192 char cbuf[64];
193 int i, m;
194 short s;
195 long l, l1;
196 vlong v;
197 File *f;
198 Posn p0, p1, p;
199 Range r;
200 String *str;
201 char *c, *wdir;
202 Rune *rp;
203 Plumbmsg *pm;
204
205 if(type > TMAX)
206 panic("inmesg");
207
208 journal(0, tname[type]);
209
210 inp = indata;
211 switch(type){
212 case -1:
213 panic("rcv error");
214
215 default:
216 fprint(2, "unknown type %d\n", type);
217 panic("rcv unknown");
218
219 case Tversion:
220 tversion = inshort();
221 journaln(0, tversion);
222 break;
223
224 case Tstartcmdfile:
225 v = invlong(); /* for 64-bit pointers */
226 journaln(0, v);
227 Strdupl(&genstr, samname);
228 cmd = newfile();
229 cmd->unread = 0;
230 outTsv(Hbindname, cmd->tag, v);
231 outTs(Hcurrent, cmd->tag);
232 logsetname(cmd, &genstr);
233 cmd->rasp = listalloc('P');
234 cmd->mod = 0;
235 if(cmdstr.n){
236 loginsert(cmd, 0L, cmdstr.s, cmdstr.n);
237 Strdelete(&cmdstr, 0L, (Posn)cmdstr.n);
238 }
239 fileupdate(cmd, FALSE, TRUE);
240 outT0(Hunlock);
241 break;
242
243 case Tcheck:
244 /* go through whichfile to check the tag */
245 outTs(Hcheck, whichfile(inshort())->tag);
246 break;
247
248 case Trequest:
249 f = whichfile(inshort());
250 p0 = inlong();
251 p1 = p0+inshort();
252 journaln(0, p0);
253 journaln(0, p1-p0);
254 if(f->unread)
255 panic("Trequest: unread");
256 if(p1>f->b.nc)
257 p1 = f->b.nc;
258 if(p0>f->b.nc) /* can happen e.g. scrolling during comma…
259 p0 = f->b.nc;
260 if(p0 == p1){
261 i = 0;
262 r.p1 = r.p2 = p0;
263 }else{
264 r = rdata(f->rasp, p0, p1-p0);
265 i = r.p2-r.p1;
266 bufread(&f->b, r.p1, buf, i);
267 }
268 buf[i]=0;
269 outTslS(Hdata, f->tag, r.p1, tmprstr(buf, i+1));
270 break;
271
272 case Torigin:
273 s = inshort();
274 l = inlong();
275 l1 = inlong();
276 journaln(0, l1);
277 lookorigin(whichfile(s), l, l1);
278 break;
279
280 case Tstartfile:
281 termlocked++;
282 f = whichfile(inshort());
283 if(!f->rasp) /* this might be a duplicate message…
284 f->rasp = listalloc('P');
285 current(f);
286 outTsv(Hbindname, f->tag, invlong()); /* for 64-b…
287 outTs(Hcurrent, f->tag);
288 journaln(0, f->tag);
289 if(f->unread)
290 load(f);
291 else{
292 if(f->b.nc>0){
293 rgrow(f->rasp, 0L, f->b.nc);
294 outTsll(Hgrow, f->tag, 0L, f->b.nc);
295 }
296 outTs(Hcheck0, f->tag);
297 moveto(f, f->dot.r);
298 }
299 break;
300
301 case Tworkfile:
302 i = inshort();
303 f = whichfile(i);
304 current(f);
305 f->dot.r.p1 = inlong();
306 f->dot.r.p2 = inlong();
307 f->tdot = f->dot.r;
308 journaln(0, i);
309 journaln(0, f->dot.r.p1);
310 journaln(0, f->dot.r.p2);
311 break;
312
313 case Ttype:
314 f = whichfile(inshort());
315 p0 = inlong();
316 journaln(0, p0);
317 journal(0, (char*)inp);
318 str = tmpcstr((char*)inp);
319 i = str->n;
320 loginsert(f, p0, str->s, str->n);
321 if(fileupdate(f, FALSE, FALSE))
322 seq++;
323 if(f==cmd && p0==f->b.nc-i && i>0 && str->s[i-1]=='\n'){
324 freetmpstr(str);
325 termlocked++;
326 termcommand();
327 }else
328 freetmpstr(str);
329 f->dot.r.p1 = f->dot.r.p2 = p0+i; /* terminal knows this…
330 f->tdot = f->dot.r;
331 break;
332
333 case Tcut:
334 f = whichfile(inshort());
335 p0 = inlong();
336 p1 = inlong();
337 journaln(0, p0);
338 journaln(0, p1);
339 logdelete(f, p0, p1);
340 if(fileupdate(f, FALSE, FALSE))
341 seq++;
342 f->dot.r.p1 = f->dot.r.p2 = p0;
343 f->tdot = f->dot.r; /* terminal knows the value of dot…
344 break;
345
346 case Tpaste:
347 f = whichfile(inshort());
348 p0 = inlong();
349 journaln(0, p0);
350 for(l=0; l<snarfbuf.nc; l+=m){
351 m = snarfbuf.nc-l;
352 if(m>BLOCKSIZE)
353 m = BLOCKSIZE;
354 bufread(&snarfbuf, l, genbuf, m);
355 loginsert(f, p0, tmprstr(genbuf, m)->s, m);
356 }
357 if(fileupdate(f, FALSE, TRUE))
358 seq++;
359 f->dot.r.p1 = p0;
360 f->dot.r.p2 = p0+snarfbuf.nc;
361 f->tdot.p1 = -1; /* force telldot to tell (arguably a BU…
362 telldot(f);
363 outTs(Hunlockfile, f->tag);
364 break;
365
366 case Tsnarf:
367 i = inshort();
368 p0 = inlong();
369 p1 = inlong();
370 snarf(whichfile(i), p0, p1, &snarfbuf, 0);
371 break;
372
373 case Tstartnewfile:
374 v = invlong();
375 Strdupl(&genstr, empty);
376 f = newfile();
377 f->rasp = listalloc('P');
378 outTsv(Hbindname, f->tag, v);
379 logsetname(f, &genstr);
380 outTs(Hcurrent, f->tag);
381 current(f);
382 load(f);
383 break;
384
385 case Twrite:
386 termlocked++;
387 i = inshort();
388 journaln(0, i);
389 f = whichfile(i);
390 addr.r.p1 = 0;
391 addr.r.p2 = f->b.nc;
392 if(f->name.s[0] == 0)
393 error(Enoname);
394 Strduplstr(&genstr, &f->name);
395 writef(f);
396 break;
397
398 case Tclose:
399 termlocked++;
400 i = inshort();
401 journaln(0, i);
402 f = whichfile(i);
403 current(f);
404 trytoclose(f);
405 /* if trytoclose fails, will error out */
406 delete(f);
407 break;
408
409 case Tlook:
410 f = whichfile(inshort());
411 termlocked++;
412 p0 = inlong();
413 p1 = inlong();
414 journaln(0, p0);
415 journaln(0, p1);
416 setgenstr(f, p0, p1);
417 for(l = 0; l<genstr.n; l++){
418 i = genstr.s[l];
419 if(utfrune(".*+?(|)\\[]^$", i)){
420 str = tmpcstr("\\");
421 Strinsert(&genstr, str, l++);
422 freetmpstr(str);
423 }
424 }
425 Straddc(&genstr, '\0');
426 nextmatch(f, &genstr, p1, 1);
427 moveto(f, sel.p[0]);
428 break;
429
430 case Tsearch:
431 termlocked++;
432 if(curfile == 0)
433 error(Enofile);
434 if(lastpat.s[0] == 0)
435 panic("Tsearch");
436 nextmatch(curfile, &lastpat, curfile->dot.r.p2, 1);
437 moveto(curfile, sel.p[0]);
438 break;
439
440 case Tsend:
441 termlocked++;
442 inshort(); /* ignored */
443 p0 = inlong();
444 p1 = inlong();
445 setgenstr(cmd, p0, p1);
446 bufreset(&snarfbuf);
447 bufinsert(&snarfbuf, (Posn)0, genstr.s, genstr.n);
448 outTl(Hsnarflen, genstr.n);
449 if(genstr.s[genstr.n-1] != '\n')
450 Straddc(&genstr, '\n');
451 loginsert(cmd, cmd->b.nc, genstr.s, genstr.n);
452 fileupdate(cmd, FALSE, TRUE);
453 cmd->dot.r.p1 = cmd->dot.r.p2 = cmd->b.nc;
454 telldot(cmd);
455 termcommand();
456 break;
457
458 case Tdclick:
459 f = whichfile(inshort());
460 p1 = inlong();
461 doubleclick(f, p1);
462 f->tdot.p1 = f->tdot.p2 = p1;
463 telldot(f);
464 outTs(Hunlockfile, f->tag);
465 break;
466
467 case Tstartsnarf:
468 if (snarfbuf.nc <= 0) { /* nothing to export */
469 outTs(Hsetsnarf, 0);
470 break;
471 }
472 c = 0;
473 i = 0;
474 m = snarfbuf.nc;
475 if(m > SNARFSIZE) {
476 m = SNARFSIZE;
477 dprint("?warning: snarf buffer truncated\n");
478 }
479 rp = malloc(m*sizeof(Rune));
480 if(rp){
481 bufread(&snarfbuf, 0, rp, m);
482 c = Strtoc(tmprstr(rp, m));
483 free(rp);
484 i = strlen(c);
485 }
486 outTs(Hsetsnarf, i);
487 if(c){
488 Write(1, c, i);
489 free(c);
490 } else
491 dprint("snarf buffer too long\n");
492 break;
493
494 case Tsetsnarf:
495 m = inshort();
496 if(m > SNARFSIZE)
497 error(Etoolong);
498 c = malloc(m+1);
499 if(c){
500 for(i=0; i<m; i++)
501 c[i] = rcvchar();
502 c[m] = 0;
503 str = tmpcstr(c);
504 free(c);
505 bufreset(&snarfbuf);
506 bufinsert(&snarfbuf, (Posn)0, str->s, str->n);
507 freetmpstr(str);
508 outT0(Hunlock);
509 }
510 break;
511
512 case Tack:
513 waitack = 0;
514 break;
515 #if 0
516 case Tplumb:
517 f = whichfile(inshort());
518 p0 = inlong();
519 p1 = inlong();
520 pm = emalloc(sizeof(Plumbmsg));
521 pm->src = strdup("sam");
522 pm->dst = 0;
523 /* construct current directory */
524 c = Strtoc(&f->name);
525 if(c[0] == '/')
526 pm->wdir = c;
527 else{
528 wdir = emalloc(1024);
529 getwd(wdir, 1024);
530 pm->wdir = emalloc(1024);
531 snprint(pm->wdir, 1024, "%s/%s", wdir, c);
532 cleanname(pm->wdir);
533 free(wdir);
534 free(c);
535 }
536 c = strrchr(pm->wdir, '/');
537 if(c)
538 *c = '\0';
539 pm->type = strdup("text");
540 if(p1 > p0)
541 pm->attr = nil;
542 else{
543 p = p0;
544 while(p0>0 && (i=filereadc(f, p0 - 1))!=' ' && i…
545 p0--;
546 while(p1<f->b.nc && (i=filereadc(f, p1))!=' ' &&…
547 p1++;
548 sprint(cbuf, "click=%ld", p-p0);
549 pm->attr = plumbunpackattr(cbuf);
550 }
551 if(p0==p1 || p1-p0>=BLOCKSIZE){
552 plumbfree(pm);
553 break;
554 }
555 setgenstr(f, p0, p1);
556 pm->data = Strtoc(&genstr);
557 pm->ndata = strlen(pm->data);
558 c = plumbpack(pm, &i);
559 if(c != 0){
560 outTs(Hplumb, i);
561 Write(1, c, i);
562 free(c);
563 }
564 plumbfree(pm);
565 break;
566 #endif
567 case Texit:
568 exits(0);
569 }
570 return TRUE;
571 }
572
573 void
574 snarf(File *f, Posn p1, Posn p2, Buffer *buf, int emptyok)
575 {
576 Posn l;
577 int i;
578
579 if(!emptyok && p1==p2)
580 return;
581 bufreset(buf);
582 /* Stage through genbuf to avoid compaction problems (vestigial)…
583 if(p2 > f->b.nc){
584 fprint(2, "bad snarf addr p1=%ld p2=%ld f->b.nc=%d\n", p…
585 p2 = f->b.nc;
586 }
587 for(l=p1; l<p2; l+=i){
588 i = p2-l>BLOCKSIZE? BLOCKSIZE : p2-l;
589 bufread(&f->b, l, genbuf, i);
590 bufinsert(buf, buf->nc, tmprstr(genbuf, i)->s, i);
591 }
592 }
593
594 int
595 inshort(void)
596 {
597 ushort n;
598
599 n = inp[0] | (inp[1]<<8);
600 inp += 2;
601 return n;
602 }
603
604 long
605 inlong(void)
606 {
607 ulong n;
608
609 n = inp[0] | (inp[1]<<8) | (inp[2]<<16) | (inp[3]<<24);
610 inp += 4;
611 return n;
612 }
613
614 vlong
615 invlong(void)
616 {
617 vlong v;
618
619 v = (inp[7]<<24) | (inp[6]<<16) | (inp[5]<<8) | inp[4];
620 v = (v<<16) | (inp[3]<<8) | inp[2];
621 v = (v<<16) | (inp[1]<<8) | inp[0];
622 inp += 8;
623 return v;
624 }
625
626 void
627 setgenstr(File *f, Posn p0, Posn p1)
628 {
629 if(p0 != p1){
630 if(p1-p0 >= TBLOCKSIZE)
631 error(Etoolong);
632 Strinsure(&genstr, p1-p0);
633 bufread(&f->b, p0, genbuf, p1-p0);
634 memmove(genstr.s, genbuf, RUNESIZE*(p1-p0));
635 genstr.n = p1-p0;
636 }else{
637 if(snarfbuf.nc == 0)
638 error(Eempty);
639 if(snarfbuf.nc > TBLOCKSIZE)
640 error(Etoolong);
641 bufread(&snarfbuf, (Posn)0, genbuf, snarfbuf.nc);
642 Strinsure(&genstr, snarfbuf.nc);
643 memmove(genstr.s, genbuf, RUNESIZE*snarfbuf.nc);
644 genstr.n = snarfbuf.nc;
645 }
646 }
647
648 void
649 outT0(Hmesg type)
650 {
651 outstart(type);
652 outsend();
653 }
654
655 void
656 outTl(Hmesg type, long l)
657 {
658 outstart(type);
659 outlong(l);
660 outsend();
661 }
662
663 void
664 outTs(Hmesg type, int s)
665 {
666 outstart(type);
667 journaln(1, s);
668 outshort(s);
669 outsend();
670 }
671
672 void
673 outS(String *s)
674 {
675 char *c;
676 int i;
677
678 c = Strtoc(s);
679 i = strlen(c);
680 outcopy(i, c);
681 if(i > 99)
682 c[99] = 0;
683 journaln(1, i);
684 journal(1, c);
685 free(c);
686 }
687
688 void
689 outTsS(Hmesg type, int s1, String *s)
690 {
691 outstart(type);
692 outshort(s1);
693 outS(s);
694 outsend();
695 }
696
697 void
698 outTslS(Hmesg type, int s1, Posn l1, String *s)
699 {
700 outstart(type);
701 outshort(s1);
702 journaln(1, s1);
703 outlong(l1);
704 journaln(1, l1);
705 outS(s);
706 outsend();
707 }
708
709 void
710 outTS(Hmesg type, String *s)
711 {
712 outstart(type);
713 outS(s);
714 outsend();
715 }
716
717 void
718 outTsllS(Hmesg type, int s1, Posn l1, Posn l2, String *s)
719 {
720 outstart(type);
721 outshort(s1);
722 outlong(l1);
723 outlong(l2);
724 journaln(1, l1);
725 journaln(1, l2);
726 outS(s);
727 outsend();
728 }
729
730 void
731 outTsll(Hmesg type, int s, Posn l1, Posn l2)
732 {
733 outstart(type);
734 outshort(s);
735 outlong(l1);
736 outlong(l2);
737 journaln(1, l1);
738 journaln(1, l2);
739 outsend();
740 }
741
742 void
743 outTsl(Hmesg type, int s, Posn l)
744 {
745 outstart(type);
746 outshort(s);
747 outlong(l);
748 journaln(1, l);
749 outsend();
750 }
751
752 void
753 outTsv(Hmesg type, int s, vlong v)
754 {
755 outstart(type);
756 outshort(s);
757 outvlong(v);
758 journaln(1, v);
759 outsend();
760 }
761
762 void
763 outstart(Hmesg type)
764 {
765 journal(1, hname[type]);
766 outmsg[0] = type;
767 outp = outmsg+3;
768 }
769
770 void
771 outcopy(int count, void *data)
772 {
773 memmove(outp, data, count);
774 outp += count;
775 }
776
777 void
778 outshort(int s)
779 {
780 *outp++ = s;
781 *outp++ = s>>8;
782 }
783
784 void
785 outlong(long l)
786 {
787 *outp++ = l;
788 *outp++ = l>>8;
789 *outp++ = l>>16;
790 *outp++ = l>>24;
791 }
792
793 void
794 outvlong(vlong v)
795 {
796 int i;
797
798 for(i = 0; i < 8; i++){
799 *outp++ = v;
800 v >>= 8;
801 }
802 }
803
804 void
805 outsend(void)
806 {
807 int outcount;
808
809 if(outp >= outdata+nelem(outdata))
810 panic("outsend");
811 outcount = outp-outmsg;
812 outcount -= 3;
813 outmsg[1] = outcount;
814 outmsg[2] = outcount>>8;
815 outmsg = outp;
816 if(!outbuffered){
817 outcount = outmsg-outdata;
818 if (write(1, (char*) outdata, outcount) != outcount)
819 rescue();
820 outmsg = outdata;
821 return;
822 }
823 }
824
825 int
826 needoutflush(void)
827 {
828 return outmsg >= outdata+DATASIZE;
829 }
830
831 void
832 outflush(void)
833 {
834 if(outmsg == outdata)
835 return;
836 outbuffered = 0;
837 /* flow control */
838 outT0(Hack);
839 waitack = 1;
840 do
841 if(rcv() == 0){
842 rescue();
843 exits("eof");
844 }
845 while(waitack);
846 outmsg = outdata;
847 outbuffered = 1;
848 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.