Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <fcall.h>
5 #include <fs.h>
6 #include "term.h"
8 #define EVENTSIZE 256
9 #define STACK 32768
11 typedef struct Event Event;
12 typedef struct Q Q;
14 struct Event
15 {
16 int c1;
17 int c2;
18 int q0;
19 int q1;
20 int flag;
21 int nb;
22 int nr;
23 char b[EVENTSIZE*UTFmax+1];
24 Rune r[EVENTSIZE+1];
25 };
27 Event blank = {
28 'M',
29 'X',
30 0, 0, 0, 1, 1,
31 { ' ', 0 },
32 { ' ', 0 },
33 };
35 struct Q
36 {
37 QLock lk;
38 int p;
39 int k;
40 };
42 Q q;
44 Fid *eventfd;
45 Fid *addrfd;
46 Fid *datafd;
47 Fid *ctlfd;
48 // int bodyfd;
50 char *typing;
51 int ntypeb;
52 int ntyper;
53 int ntypebreak;
54 int debug;
55 int rcfd;
57 char *name;
59 char **prog;
60 Channel *cwait;
61 int pid = -1;
63 int label(char*, int);
64 void error(char*);
65 void stdinproc(void*);
66 void stdoutproc(void*);
67 void type(Event*, int, Fid*, Fid*);
68 void sende(Event*, int, Fid*, Fid*, Fid*, int);
69 char *onestring(int, char**);
70 int delete(Event*);
71 void deltype(uint, uint);
72 void runproc(void*);
74 int
75 fsfidprint(Fid *fid, char *fmt, ...)
76 {
77 char buf[256];
78 va_list arg;
79 int n;
81 va_start(arg, fmt);
82 n = vsnprint(buf, sizeof buf, fmt, arg);
83 va_end(arg);
84 return fswrite(fid, buf, n);
85 }
87 void
88 usage(void)
89 {
90 fprint(2, "usage: win cmd args...\n");
91 threadexitsall("usage");
92 }
94 int
95 nopipes(void *v, char *msg)
96 {
97 USED(v);
98 if(strcmp(msg, "sys: write on closed pipe") == 0)
99 return 1;
100 return 0;
103 void
104 waitthread(void *v)
106 recvp(cwait);
107 threadexitsall(nil);
110 void
111 threadmain(int argc, char **argv)
113 int fd, id;
114 char buf[256];
115 char buf1[128];
116 Fsys *fs;
118 ARGBEGIN{
119 case 'd':
120 debug = 1;
121 break;
122 default:
123 usage();
124 }ARGEND
126 prog = argv;
128 if(argc > 0){
129 name = argv[0];
130 argc--;
131 argv++;
132 }else
133 name = "gnot";
135 threadnotify(nopipes, 1);
136 if((fs = nsmount("acme", "")) == 0)
137 sysfatal("nsmount acme: %r");
138 ctlfd = fsopen(fs, "new/ctl", ORDWR|OCEXEC);
139 if(ctlfd == 0 || fsread(ctlfd, buf, 12) != 12)
140 sysfatal("ctl: %r");
141 id = atoi(buf);
142 sprint(buf, "%d/tag", id);
143 fd = fsopenfd(fs, buf, OWRITE|OCEXEC);
144 write(fd, " Send Delete", 12);
145 close(fd);
146 sprint(buf, "%d/event", id);
147 eventfd = fsopen(fs, buf, ORDWR|OCEXEC);
148 sprint(buf, "%d/addr", id);
149 addrfd = fsopen(fs, buf, ORDWR|OCEXEC);
150 sprint(buf, "%d/data", id);
151 datafd = fsopen(fs, buf, ORDWR|OCEXEC);
152 sprint(buf, "%d/body", id);
153 /* bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC); */
154 if(eventfd==nil || addrfd==nil || datafd==nil)
155 sysfatal("data files: %r");
156 /*
157 if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0)
158 sysfatal("data files: %r");
159 */
160 fsunmount(fs);
162 cwait = threadwaitchan();
163 threadcreate(waitthread, nil, STACK);
164 pid = rcstart(argc, argv, &rcfd);
165 if(pid == -1)
166 sysfatal("exec failed");
168 getwd(buf1, sizeof buf1);
169 sprint(buf, "name %s/-%s\n0\n", buf1, name);
170 fswrite(ctlfd, buf, strlen(buf));
171 sprint(buf, "dumpdir %s/\n", buf1);
172 fswrite(ctlfd, buf, strlen(buf));
173 sprint(buf, "dump %s\n", onestring(argc, argv));
174 fswrite(ctlfd, buf, strlen(buf));
176 threadcreate(stdoutproc, nil, STACK);
177 stdinproc(nil);
180 void
181 error(char *s)
183 if(s)
184 fprint(2, "win: %s: %r\n", s);
185 else
186 s = "kill";
187 if(pid != -1)
188 postnote(PNGROUP, pid, "hangup");
189 threadexitsall(s);
192 char*
193 onestring(int argc, char **argv)
195 char *p;
196 int i, n;
197 static char buf[1024];
199 if(argc == 0)
200 return "";
201 p = buf;
202 for(i=0; i<argc; i++){
203 n = strlen(argv[i]);
204 if(p+n+1 >= buf+sizeof buf)
205 break;
206 memmove(p, argv[i], n);
207 p += n;
208 *p++ = ' ';
210 p[-1] = 0;
211 return buf;
214 int
215 getec(Fid *efd)
217 static char buf[8192];
218 static char *bufp;
219 static int nbuf;
221 if(nbuf == 0){
222 nbuf = fsread(efd, buf, sizeof buf);
223 if(nbuf <= 0)
224 error(nil);
225 bufp = buf;
227 --nbuf;
228 return *bufp++;
231 int
232 geten(Fid *efd)
234 int n, c;
236 n = 0;
237 while('0'<=(c=getec(efd)) && c<='9')
238 n = n*10+(c-'0');
239 if(c != ' ')
240 error("event number syntax");
241 return n;
244 int
245 geter(Fid *efd, char *buf, int *nb)
247 Rune r;
248 int n;
250 r = getec(efd);
251 buf[0] = r;
252 n = 1;
253 if(r < Runeself)
254 goto Return;
255 while(!fullrune(buf, n))
256 buf[n++] = getec(efd);
257 chartorune(&r, buf);
258 Return:
259 *nb = n;
260 return r;
263 void
264 gete(Fid *efd, Event *e)
266 int i, nb;
268 e->c1 = getec(efd);
269 e->c2 = getec(efd);
270 e->q0 = geten(efd);
271 e->q1 = geten(efd);
272 e->flag = geten(efd);
273 e->nr = geten(efd);
274 if(e->nr > EVENTSIZE)
275 error("event string too long");
276 e->nb = 0;
277 for(i=0; i<e->nr; i++){
278 e->r[i] = geter(efd, e->b+e->nb, &nb);
279 e->nb += nb;
281 e->r[e->nr] = 0;
282 e->b[e->nb] = 0;
283 if(getec(efd) != '\n')
284 error("event syntax 2");
287 int
288 nrunes(char *s, int nb)
290 int i, n;
291 Rune r;
293 n = 0;
294 for(i=0; i<nb; n++)
295 i += chartorune(&r, s+i);
296 return n;
299 void
300 stdinproc(void *v)
302 Fid *cfd = ctlfd;
303 Fid *efd = eventfd;
304 Fid *dfd = datafd;
305 Fid *afd = addrfd;
306 int fd0 = rcfd;
307 Event e, e2, e3, e4;
309 USED(v);
311 for(;;){
312 if(debug)
313 fprint(2, "typing[%d,%d)\n", q.p, q.p+ntyper);
314 gete(efd, &e);
315 if(debug)
316 fprint(2, "msg %c%c q[%d,%d)... ", e.c1, e.c2, e.q0, e.q1);
317 qlock(&q.lk);
318 switch(e.c1){
319 default:
320 Unknown:
321 print("unknown message %c%c\n", e.c1, e.c2);
322 break;
324 case 'E': /* write to body; can't affect us */
325 if(debug)
326 fprint(2, "shift typing %d... ", e.q1-e.q0);
327 q.p += e.q1-e.q0;
328 break;
330 case 'F': /* generated by our actions; ignore */
331 break;
333 case 'K':
334 case 'M':
335 switch(e.c2){
336 case 'I':
337 if(e.q0 < q.p){
338 if(debug)
339 fprint(2, "shift typing %d... ", e.q1-e.q0);
340 q.p += e.q1-e.q0;
342 else if(e.q0 <= q.p+ntyper){
343 if(debug)
344 fprint(2, "type... ");
345 type(&e, fd0, afd, dfd);
347 break;
349 case 'D':
350 q.p -= delete(&e);
351 break;
353 case 'x':
354 case 'X':
355 if(e.flag & 2)
356 gete(efd, &e2);
357 if(e.flag & 8){
358 gete(efd, &e3);
359 gete(efd, &e4);
361 if(e.flag&1 || (e.c2=='x' && e.nr==0 && e2.nr==0)){
362 /* send it straight back */
363 fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
364 break;
366 if(e.q0==e.q1 && (e.flag&2)){
367 e2.flag = e.flag;
368 e = e2;
370 if(e.flag & 8){
371 if(e.q1 != e.q0){
372 sende(&e, fd0, cfd, afd, dfd, 0);
373 sende(&blank, fd0, cfd, afd, dfd, 0);
375 sende(&e3, fd0, cfd, afd, dfd, 1);
376 }else if(e.q1 != e.q0)
377 sende(&e, fd0, cfd, afd, dfd, 1);
378 break;
380 case 'l':
381 case 'L':
382 /* just send it back */
383 if(e.flag & 2)
384 gete(efd, &e2);
385 fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
386 break;
388 case 'd':
389 case 'i':
390 break;
392 default:
393 goto Unknown;
396 qunlock(&q.lk);
400 void
401 stdoutproc(void *v)
403 int fd1 = rcfd;
404 Fid *afd = addrfd;
405 Fid *dfd = datafd;
406 int n, m, w, npart;
407 char *buf, *s, *t;
408 Rune r;
409 char x[16], hold[UTFmax];
411 USED(v);
412 threadnotify(nopipes, 1);
413 buf = malloc(8192+UTFmax+1);
414 npart = 0;
415 for(;;){
416 /* Let typing have a go -- maybe there's a rubout waiting. */
417 yield();
418 n = threadread(fd1, buf+npart, 8192);
419 if(n < 0)
420 error(nil);
421 if(n == 0)
422 continue;
424 /* squash NULs */
425 s = memchr(buf+npart, 0, n);
426 if(s){
427 for(t=s; s<buf+npart+n; s++)
428 if(*t = *s) /* assign = */
429 t++;
430 n = t-(buf+npart);
433 n += npart;
435 /* hold on to final partial rune */
436 npart = 0;
437 while(n>0 && (buf[n-1]&0xC0)){
438 --n;
439 npart++;
440 if((buf[n]&0xC0)!=0x80){
441 if(fullrune(buf+n, npart)){
442 w = chartorune(&r, buf+n);
443 n += w;
444 npart -= w;
446 break;
449 if(n > 0){
450 memmove(hold, buf+n, npart);
451 buf[n] = 0;
452 n = label(buf, n);
453 buf[n] = 0;
454 qlock(&q.lk);
455 m = sprint(x, "#%d", q.p);
456 if(fswrite(afd, x, m) != m)
457 error("stdout writing address");
458 if(fswrite(dfd, buf, n) != n)
459 error("stdout writing body");
460 q.p += nrunes(buf, n);
461 qunlock(&q.lk);
462 memmove(buf, hold, npart);
467 char wdir[256];
468 int
469 label(char *sr, int n)
471 char *sl, *el, *er, *r;
473 er = sr+n;
474 for(r=er-1; r>=sr; r--)
475 if(*r == '\007')
476 break;
477 if(r < sr)
478 return n;
480 el = r+1;
481 if(el-sr > sizeof wdir)
482 sr = el - sizeof wdir;
483 for(sl=el-3; sl>=sr; sl--)
484 if(sl[0]=='\033' && sl[1]==']' && sl[2]==';')
485 break;
486 if(sl < sr)
487 return n;
489 *r = 0;
490 snprint(wdir, sizeof wdir, "name %s/-%s\n0\n", sl+3, name);
491 fswrite(ctlfd, wdir, strlen(wdir));
493 memmove(sl, el, er-el);
494 n -= (el-sl);
495 return n;
498 int
499 delete(Event *e)
501 uint q0, q1;
502 int deltap;
504 q0 = e->q0;
505 q1 = e->q1;
506 if(q1 <= q.p)
507 return e->q1-e->q0;
508 if(q0 >= q.p+ntyper)
509 return 0;
510 deltap = 0;
511 if(q0 < q.p){
512 deltap = q.p-q0;
513 q0 = 0;
514 }else
515 q0 -= q.p;
516 if(q1 > q.p+ntyper)
517 q1 = ntyper;
518 else
519 q1 -= q.p;
520 deltype(q0, q1);
521 return deltap;
524 void
525 addtype(int c, uint p0, char *b, int nb, int nr)
527 int i, w;
528 Rune r;
529 uint p;
530 char *b0;
532 for(i=0; i<nb; i+=w){
533 w = chartorune(&r, b+i);
534 if((r==0x7F||r==3) && c=='K'){
535 write(rcfd, "\x7F", 1);
536 /* toss all typing */
537 q.p += ntyper+nr;
538 ntypebreak = 0;
539 ntypeb = 0;
540 ntyper = 0;
541 /* buglet: more than one delete ignored */
542 return;
544 if(r=='\n' || r==0x04)
545 ntypebreak++;
547 typing = realloc(typing, ntypeb+nb);
548 if(typing == nil)
549 error("realloc");
550 if(p0 == ntyper)
551 memmove(typing+ntypeb, b, nb);
552 else{
553 b0 = typing;
554 for(p=0; p<p0 && b0<typing+ntypeb; p++){
555 w = chartorune(&r, b0+i);
556 b0 += w;
558 if(p != p0)
559 error("typing: findrune");
560 memmove(b0+nb, b0, (typing+ntypeb)-b0);
561 memmove(b0, b, nb);
563 ntypeb += nb;
564 ntyper += nr;
567 void
568 sendtype(int fd0)
570 int i, n, nr;
572 while(ntypebreak){
573 for(i=0; i<ntypeb; i++)
574 if(typing[i]=='\n' || typing[i]==0x04){
575 n = i + (typing[i] == '\n');
576 i++;
577 if(write(fd0, typing, n) != n)
578 error("sending to program");
579 nr = nrunes(typing, i);
580 q.p += nr;
581 ntyper -= nr;
582 ntypeb -= i;
583 memmove(typing, typing+i, ntypeb);
584 ntypebreak--;
585 goto cont2;
587 print("no breakchar\n");
588 ntypebreak = 0;
589 cont2:;
593 void
594 deltype(uint p0, uint p1)
596 int w;
597 uint p, b0, b1;
598 Rune r;
600 /* advance to p0 */
601 b0 = 0;
602 for(p=0; p<p0 && b0<ntypeb; p++){
603 w = chartorune(&r, typing+b0);
604 b0 += w;
606 if(p != p0)
607 error("deltype 1");
608 /* advance to p1 */
609 b1 = b0;
610 for(; p<p1 && b1<ntypeb; p++){
611 w = chartorune(&r, typing+b1);
612 b1 += w;
613 if(r=='\n' || r==0x04)
614 ntypebreak--;
616 if(p != p1)
617 error("deltype 2");
618 memmove(typing+b0, typing+b1, ntypeb-b1);
619 ntypeb -= b1-b0;
620 ntyper -= p1-p0;
623 void
624 type(Event *e, int fd0, Fid *afd, Fid *dfd)
626 int m, n, nr;
627 char buf[128];
629 if(e->nr > 0)
630 addtype(e->c1, e->q0-q.p, e->b, e->nb, e->nr);
631 else{
632 m = e->q0;
633 while(m < e->q1){
634 n = sprint(buf, "#%d", m);
635 fswrite(afd, buf, n);
636 n = fsread(dfd, buf, sizeof buf);
637 nr = nrunes(buf, n);
638 while(m+nr > e->q1){
639 do; while(n>0 && (buf[--n]&0xC0)==0x80);
640 --nr;
642 if(n == 0)
643 break;
644 addtype(e->c1, m-q.p, buf, n, nr);
645 m += nr;
648 sendtype(fd0);
651 void
652 sende(Event *e, int fd0, Fid *cfd, Fid *afd, Fid *dfd, int donl)
654 int l, m, n, nr, lastc, end;
655 char abuf[16], buf[128];
657 end = q.p+ntyper;
658 l = sprint(abuf, "#%d", end);
659 fswrite(afd, abuf, l);
660 if(e->nr > 0){
661 fswrite(dfd, e->b, e->nb);
662 addtype(e->c1, ntyper, e->b, e->nb, e->nr);
663 lastc = e->r[e->nr-1];
664 }else{
665 m = e->q0;
666 lastc = 0;
667 while(m < e->q1){
668 n = sprint(buf, "#%d", m);
669 fswrite(afd, buf, n);
670 n = fsread(dfd, buf, sizeof buf);
671 nr = nrunes(buf, n);
672 while(m+nr > e->q1){
673 do; while(n>0 && (buf[--n]&0xC0)==0x80);
674 --nr;
676 if(n == 0)
677 break;
678 l = sprint(abuf, "#%d", end);
679 fswrite(afd, abuf, l);
680 fswrite(dfd, buf, n);
681 addtype(e->c1, ntyper, buf, n, nr);
682 lastc = buf[n-1];
683 m += nr;
684 end += nr;
687 if(donl && lastc!='\n'){
688 fswrite(dfd, "\n", 1);
689 addtype(e->c1, ntyper, "\n", 1, 1);
691 fswrite(cfd, "dot=addr", 8);
692 sendtype(fd0);