Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <fcall.h>
5 #include <fs.h>
7 #define EVENTSIZE 256
8 #define STACK 32768
10 typedef struct Event Event;
11 typedef struct Q Q;
13 struct Event
14 {
15 int c1;
16 int c2;
17 int q0;
18 int q1;
19 int flag;
20 int nb;
21 int nr;
22 char b[EVENTSIZE*UTFmax+1];
23 Rune r[EVENTSIZE+1];
24 };
26 Event blank = {
27 'M',
28 'X',
29 0, 0, 0, 1, 1,
30 { ' ', 0 },
31 { ' ', 0 },
32 };
34 struct Q
35 {
36 QLock lk;
37 int p;
38 int k;
39 };
41 Q q;
43 Fid *eventfd;
44 Fid *addrfd;
45 Fid *datafd;
46 Fid *ctlfd;
47 // int bodyfd;
49 char *typing;
50 int ntypeb;
51 int ntyper;
52 int ntypebreak;
53 int debug;
54 char *name;
56 char **prog;
57 int p[2];
58 Channel *cpid;
59 Channel *cwait;
60 int pid = -1;
62 int label(char*, int);
63 void error(char*);
64 void stdinproc(void*);
65 void stdoutproc(void*);
66 void type(Event*, int, Fid*, Fid*);
67 void sende(Event*, int, Fid*, Fid*, Fid*, int);
68 char *onestring(int, char**);
69 int delete(Event*);
70 void deltype(uint, uint);
71 void runproc(void*);
73 int
74 fsfidprint(Fid *fid, char *fmt, ...)
75 {
76 char buf[256];
77 va_list arg;
78 int n;
80 va_start(arg, fmt);
81 n = vsnprint(buf, sizeof buf, fmt, arg);
82 va_end(arg);
83 return fswrite(fid, buf, n);
84 }
86 void
87 usage(void)
88 {
89 fprint(2, "usage: win cmd args...\n");
90 threadexitsall("usage");
91 }
93 int
94 nopipes(void *v, char *msg)
95 {
96 USED(v);
97 if(strcmp(msg, "sys: write on closed pipe") == 0)
98 return 1;
99 return 0;
102 void
103 waitthread(void *v)
105 recvp(cwait);
106 threadexitsall(nil);
109 void
110 threadmain(int argc, char **argv)
112 int fd, id;
113 char buf[256];
114 char buf1[128];
115 Fsys *fs;
117 ARGBEGIN{
118 case 'd':
119 debug = 1;
120 break;
121 default:
122 usage();
123 }ARGEND
125 prog = argv;
127 if(argc > 0)
128 name = argv[0];
129 else
130 name = "gnot";
132 threadnotify(nopipes, 1);
133 if((fs = nsmount("acme", "")) < 0)
134 sysfatal("nsmount acme: %r");
135 ctlfd = fsopen(fs, "new/ctl", ORDWR|OCEXEC);
136 if(ctlfd < 0 || fsread(ctlfd, buf, 12) != 12)
137 sysfatal("ctl: %r");
138 id = atoi(buf);
139 sprint(buf, "%d/tag", id);
140 fd = fsopenfd(fs, buf, OWRITE|OCEXEC);
141 write(fd, " Send Delete", 12);
142 close(fd);
143 sprint(buf, "%d/event", id);
144 eventfd = fsopen(fs, buf, ORDWR|OCEXEC);
145 sprint(buf, "%d/addr", id);
146 addrfd = fsopen(fs, buf, ORDWR|OCEXEC);
147 sprint(buf, "%d/data", id);
148 datafd = fsopen(fs, buf, ORDWR|OCEXEC);
149 sprint(buf, "%d/body", id);
150 /* bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC); */
151 if(eventfd==nil || addrfd==nil || datafd==nil)
152 sysfatal("data files: %r");
153 /*
154 if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0)
155 sysfatal("data files: %r");
156 */
157 fsunmount(fs);
159 if(pipe(p) < 0)
160 sysfatal("pipe: %r");
162 cpid = chancreate(sizeof(ulong), 1);
163 cwait = threadwaitchan();
164 threadcreate(waitthread, nil, STACK);
165 threadcreate(runproc, nil, STACK);
166 pid = recvul(cpid);
167 if(pid == -1)
168 sysfatal("exec failed");
170 getwd(buf1, sizeof buf1);
171 sprint(buf, "name %s/-%s\n0\n", buf1, name);
172 fswrite(ctlfd, buf, strlen(buf));
173 sprint(buf, "dumpdir %s/\n", buf1);
174 fswrite(ctlfd, buf, strlen(buf));
175 sprint(buf, "dump %s\n", onestring(argc, argv));
176 fswrite(ctlfd, buf, strlen(buf));
178 threadcreate(stdoutproc, nil, STACK);
179 stdinproc(nil);
182 char *shell[] = { "rc", "-i", 0 };
183 void
184 runproc(void *v)
186 int fd[3];
187 char *sh;
189 USED(v);
191 fd[0] = p[1];
192 // fd[1] = bodyfd;
193 // fd[2] = bodyfd;
194 fd[1] = p[1];
195 fd[2] = p[1];
197 if(prog[0] == nil){
198 prog = shell;
199 if((sh = getenv("SHELL")) != nil)
200 shell[0] = sh;
202 threadexec(cpid, fd, prog[0], prog);
203 threadexits(nil);
206 void
207 error(char *s)
209 if(s)
210 fprint(2, "win: %s: %r\n", s);
211 else
212 s = "kill";
213 if(pid != -1)
214 postnote(PNGROUP, pid, "hangup");
215 threadexitsall(s);
218 char*
219 onestring(int argc, char **argv)
221 char *p;
222 int i, n;
223 static char buf[1024];
225 if(argc == 0)
226 return "";
227 p = buf;
228 for(i=0; i<argc; i++){
229 n = strlen(argv[i]);
230 if(p+n+1 >= buf+sizeof buf)
231 break;
232 memmove(p, argv[i], n);
233 p += n;
234 *p++ = ' ';
236 p[-1] = 0;
237 return buf;
240 int
241 getec(Fid *efd)
243 static char buf[8192];
244 static char *bufp;
245 static int nbuf;
247 if(nbuf == 0){
248 nbuf = fsread(efd, buf, sizeof buf);
249 if(nbuf <= 0)
250 error(nil);
251 bufp = buf;
253 --nbuf;
254 return *bufp++;
257 int
258 geten(Fid *efd)
260 int n, c;
262 n = 0;
263 while('0'<=(c=getec(efd)) && c<='9')
264 n = n*10+(c-'0');
265 if(c != ' ')
266 error("event number syntax");
267 return n;
270 int
271 geter(Fid *efd, char *buf, int *nb)
273 Rune r;
274 int n;
276 r = getec(efd);
277 buf[0] = r;
278 n = 1;
279 if(r < Runeself)
280 goto Return;
281 while(!fullrune(buf, n))
282 buf[n++] = getec(efd);
283 chartorune(&r, buf);
284 Return:
285 *nb = n;
286 return r;
289 void
290 gete(Fid *efd, Event *e)
292 int i, nb;
294 e->c1 = getec(efd);
295 e->c2 = getec(efd);
296 e->q0 = geten(efd);
297 e->q1 = geten(efd);
298 e->flag = geten(efd);
299 e->nr = geten(efd);
300 if(e->nr > EVENTSIZE)
301 error("event string too long");
302 e->nb = 0;
303 for(i=0; i<e->nr; i++){
304 e->r[i] = geter(efd, e->b+e->nb, &nb);
305 e->nb += nb;
307 e->r[e->nr] = 0;
308 e->b[e->nb] = 0;
309 if(getec(efd) != '\n')
310 error("event syntax 2");
313 int
314 nrunes(char *s, int nb)
316 int i, n;
317 Rune r;
319 n = 0;
320 for(i=0; i<nb; n++)
321 i += chartorune(&r, s+i);
322 return n;
325 void
326 stdinproc(void *v)
328 Fid *cfd = ctlfd;
329 Fid *efd = eventfd;
330 Fid *dfd = datafd;
331 Fid *afd = addrfd;
332 int fd0 = p[0];
333 Event e, e2, e3, e4;
335 USED(v);
337 for(;;){
338 if(debug)
339 fprint(2, "typing[%d,%d)\n", q.p, q.p+ntyper);
340 gete(efd, &e);
341 if(debug)
342 fprint(2, "msg %c%c q[%d,%d)... ", e.c1, e.c2, e.q0, e.q1);
343 qlock(&q.lk);
344 switch(e.c1){
345 default:
346 Unknown:
347 print("unknown message %c%c\n", e.c1, e.c2);
348 break;
350 case 'E': /* write to body; can't affect us */
351 if(debug)
352 fprint(2, "shift typing %d... ", e.q1-e.q0);
353 q.p += e.q1-e.q0;
354 break;
356 case 'F': /* generated by our actions; ignore */
357 break;
359 case 'K':
360 case 'M':
361 switch(e.c2){
362 case 'I':
363 if(e.q0 < q.p){
364 if(debug)
365 fprint(2, "shift typing %d... ", e.q1-e.q0);
366 q.p += e.q1-e.q0;
368 else if(e.q0 <= q.p+ntyper){
369 if(debug)
370 fprint(2, "type... ");
371 type(&e, fd0, afd, dfd);
373 break;
375 case 'D':
376 q.p -= delete(&e);
377 break;
379 case 'x':
380 case 'X':
381 if(e.flag & 2)
382 gete(efd, &e2);
383 if(e.flag & 8){
384 gete(efd, &e3);
385 gete(efd, &e4);
387 if(e.flag&1 || (e.c2=='x' && e.nr==0 && e2.nr==0)){
388 /* send it straight back */
389 fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
390 break;
392 if(e.q0==e.q1 && (e.flag&2)){
393 e2.flag = e.flag;
394 e = e2;
396 if(e.flag & 8){
397 if(e.q1 != e.q0){
398 sende(&e, fd0, cfd, afd, dfd, 0);
399 sende(&blank, fd0, cfd, afd, dfd, 0);
401 sende(&e3, fd0, cfd, afd, dfd, 1);
402 }else if(e.q1 != e.q0)
403 sende(&e, fd0, cfd, afd, dfd, 1);
404 break;
406 case 'l':
407 case 'L':
408 /* just send it back */
409 if(e.flag & 2)
410 gete(efd, &e2);
411 fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
412 break;
414 case 'd':
415 case 'i':
416 break;
418 default:
419 goto Unknown;
422 qunlock(&q.lk);
426 void
427 stdoutproc(void *v)
429 int fd1 = p[0];
430 Fid *afd = addrfd;
431 Fid *dfd = datafd;
432 int n, m, w, npart;
433 char *buf, *s, *t;
434 Rune r;
435 char x[16], hold[UTFmax];
437 USED(v);
438 threadnotify(nopipes, 1);
439 buf = malloc(8192+UTFmax+1);
440 npart = 0;
441 for(;;){
442 n = threadread(fd1, buf+npart, 8192);
443 if(n < 0)
444 error(nil);
445 if(n == 0)
446 continue;
448 /* squash NULs */
449 s = memchr(buf+npart, 0, n);
450 if(s){
451 for(t=s; s<buf+npart+n; s++)
452 if(*t = *s) /* assign = */
453 t++;
454 n = t-(buf+npart);
457 n += npart;
459 /* hold on to final partial rune */
460 npart = 0;
461 while(n>0 && (buf[n-1]&0xC0)){
462 --n;
463 npart++;
464 if((buf[n]&0xC0)!=0x80){
465 if(fullrune(buf+n, npart)){
466 w = chartorune(&r, buf+n);
467 n += w;
468 npart -= w;
470 break;
473 if(n > 0){
474 memmove(hold, buf+n, npart);
475 buf[n] = 0;
476 n = label(buf, n);
477 buf[n] = 0;
478 qlock(&q.lk);
479 m = sprint(x, "#%d", q.p);
480 if(fswrite(afd, x, m) != m)
481 error("stdout writing address");
482 if(fswrite(dfd, buf, n) != n)
483 error("stdout writing body");
484 q.p += nrunes(buf, n);
485 qunlock(&q.lk);
486 memmove(buf, hold, npart);
491 char wdir[256];
492 int
493 label(char *sr, int n)
495 char *sl, *el, *er, *r;
497 er = sr+n;
498 for(r=er-1; r>=sr; r--)
499 if(*r == '\007')
500 break;
501 if(r < sr)
502 return n;
504 el = r+1;
505 if(el-sr > sizeof wdir)
506 sr = el - sizeof wdir;
507 for(sl=el-3; sl>=sr; sl--)
508 if(sl[0]=='\033' && sl[1]==']' && sl[2]==';')
509 break;
510 if(sl < sr)
511 return n;
513 *r = 0;
514 snprint(wdir, sizeof wdir, "name %s/-%s\n0\n", sl+3, name);
515 fswrite(ctlfd, wdir, strlen(wdir));
517 memmove(sl, el, er-el);
518 n -= (el-sl);
519 return n;
522 int
523 delete(Event *e)
525 uint q0, q1;
526 int deltap;
528 q0 = e->q0;
529 q1 = e->q1;
530 if(q1 <= q.p)
531 return e->q1-e->q0;
532 if(q0 >= q.p+ntyper)
533 return 0;
534 deltap = 0;
535 if(q0 < q.p){
536 deltap = q.p-q0;
537 q0 = 0;
538 }else
539 q0 -= q.p;
540 if(q1 > q.p+ntyper)
541 q1 = ntyper;
542 else
543 q1 -= q.p;
544 deltype(q0, q1);
545 return deltap;
548 void
549 addtype(int c, uint p0, char *b, int nb, int nr)
551 int i, w;
552 Rune r;
553 uint p;
554 char *b0;
556 for(i=0; i<nb; i+=w){
557 w = chartorune(&r, b+i);
558 if((r==0x7F||r==3) && c=='K'){
559 postnote(PNGROUP, pid, "interrupt");
560 /* toss all typing */
561 q.p += ntyper+nr;
562 ntypebreak = 0;
563 ntypeb = 0;
564 ntyper = 0;
565 /* buglet: more than one delete ignored */
566 return;
568 if(r=='\n' || r==0x04)
569 ntypebreak++;
571 typing = realloc(typing, ntypeb+nb);
572 if(typing == nil)
573 error("realloc");
574 if(p0 == ntyper)
575 memmove(typing+ntypeb, b, nb);
576 else{
577 b0 = typing;
578 for(p=0; p<p0 && b0<typing+ntypeb; p++){
579 w = chartorune(&r, b0+i);
580 b0 += w;
582 if(p != p0)
583 error("typing: findrune");
584 memmove(b0+nb, b0, (typing+ntypeb)-b0);
585 memmove(b0, b, nb);
587 ntypeb += nb;
588 ntyper += nr;
591 void
592 sendtype(int fd0)
594 int i, n, nr;
596 while(ntypebreak){
597 for(i=0; i<ntypeb; i++)
598 if(typing[i]=='\n' || typing[i]==0x04){
599 n = i + (typing[i] == '\n');
600 i++;
601 if(write(fd0, typing, n) != n)
602 error("sending to program");
603 nr = nrunes(typing, i);
604 q.p += nr;
605 ntyper -= nr;
606 ntypeb -= i;
607 memmove(typing, typing+i, ntypeb);
608 ntypebreak--;
609 goto cont2;
611 print("no breakchar\n");
612 ntypebreak = 0;
613 cont2:;
617 void
618 deltype(uint p0, uint p1)
620 int w;
621 uint p, b0, b1;
622 Rune r;
624 /* advance to p0 */
625 b0 = 0;
626 for(p=0; p<p0 && b0<ntypeb; p++){
627 w = chartorune(&r, typing+b0);
628 b0 += w;
630 if(p != p0)
631 error("deltype 1");
632 /* advance to p1 */
633 b1 = b0;
634 for(; p<p1 && b1<ntypeb; p++){
635 w = chartorune(&r, typing+b1);
636 b1 += w;
637 if(r=='\n' || r==0x04)
638 ntypebreak--;
640 if(p != p1)
641 error("deltype 2");
642 memmove(typing+b0, typing+b1, ntypeb-b1);
643 ntypeb -= b1-b0;
644 ntyper -= p1-p0;
647 void
648 type(Event *e, int fd0, Fid *afd, Fid *dfd)
650 int m, n, nr;
651 char buf[128];
653 if(e->nr > 0)
654 addtype(e->c1, e->q0-q.p, e->b, e->nb, e->nr);
655 else{
656 m = e->q0;
657 while(m < e->q1){
658 n = sprint(buf, "#%d", m);
659 fswrite(afd, buf, n);
660 n = fsread(dfd, buf, sizeof buf);
661 nr = nrunes(buf, n);
662 while(m+nr > e->q1){
663 do; while(n>0 && (buf[--n]&0xC0)==0x80);
664 --nr;
666 if(n == 0)
667 break;
668 addtype(e->c1, m-q.p, buf, n, nr);
669 m += nr;
672 sendtype(fd0);
675 void
676 sende(Event *e, int fd0, Fid *cfd, Fid *afd, Fid *dfd, int donl)
678 int l, m, n, nr, lastc, end;
679 char abuf[16], buf[128];
681 end = q.p+ntyper;
682 l = sprint(abuf, "#%d", end);
683 fswrite(afd, abuf, l);
684 if(e->nr > 0){
685 fswrite(dfd, e->b, e->nb);
686 addtype(e->c1, ntyper, e->b, e->nb, e->nr);
687 lastc = e->r[e->nr-1];
688 }else{
689 m = e->q0;
690 lastc = 0;
691 while(m < e->q1){
692 n = sprint(buf, "#%d", m);
693 fswrite(afd, buf, n);
694 n = fsread(dfd, buf, sizeof buf);
695 nr = nrunes(buf, n);
696 while(m+nr > e->q1){
697 do; while(n>0 && (buf[--n]&0xC0)==0x80);
698 --nr;
700 if(n == 0)
701 break;
702 l = sprint(abuf, "#%d", end);
703 fswrite(afd, abuf, l);
704 fswrite(dfd, buf, n);
705 addtype(e->c1, ntyper, buf, n, nr);
706 lastc = buf[n-1];
707 m += nr;
708 end += nr;
711 if(donl && lastc!='\n'){
712 fswrite(dfd, "\n", 1);
713 addtype(e->c1, ntyper, "\n", 1, 1);
715 fswrite(cfd, "dot=addr", 8);
716 sendtype(fd0);