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 int noecho = 1;
10 #define EVENTSIZE 256
11 #define STACK 32768
13 typedef struct Event Event;
14 typedef struct Q Q;
16 struct Event
17 {
18 int c1;
19 int c2;
20 int q0;
21 int q1;
22 int flag;
23 int nb;
24 int nr;
25 char b[EVENTSIZE*UTFmax+1];
26 Rune r[EVENTSIZE+1];
27 };
29 Event blank = {
30 'M',
31 'X',
32 0, 0, 0, 1, 1,
33 { ' ', 0 },
34 { ' ', 0 },
35 };
37 struct Q
38 {
39 QLock lk;
40 int p;
41 int k;
42 };
44 Q q;
46 Fid *eventfd;
47 Fid *addrfd;
48 Fid *datafd;
49 Fid *ctlfd;
50 // int bodyfd;
52 char *typing;
53 int ntypeb;
54 int ntyper;
55 int ntypebreak;
56 int debug;
57 int rcfd;
59 char *name;
61 char **prog;
62 Channel *cwait;
63 int pid = -1;
65 int label(char*, int);
66 void error(char*);
67 void stdinproc(void*);
68 void stdoutproc(void*);
69 void type(Event*, int, Fid*, Fid*);
70 void sende(Event*, int, Fid*, Fid*, Fid*, int);
71 char *onestring(int, char**);
72 int delete(Event*);
73 void deltype(uint, uint);
74 void runproc(void*);
76 int
77 fsfidprint(Fid *fid, char *fmt, ...)
78 {
79 char buf[256];
80 va_list arg;
81 int n;
83 va_start(arg, fmt);
84 n = vsnprint(buf, sizeof buf, fmt, arg);
85 va_end(arg);
86 return fswrite(fid, buf, n);
87 }
89 void
90 usage(void)
91 {
92 fprint(2, "usage: win cmd args...\n");
93 threadexitsall("usage");
94 }
96 int
97 nopipes(void *v, char *msg)
98 {
99 USED(v);
100 if(strcmp(msg, "sys: write on closed pipe") == 0)
101 return 1;
102 return 0;
105 void
106 waitthread(void *v)
108 recvp(cwait);
109 threadexitsall(nil);
112 void
113 threadmain(int argc, char **argv)
115 int fd, id;
116 char buf[256];
117 char buf1[128];
118 Fsys *fs;
120 ARGBEGIN{
121 case 'd':
122 debug = 1;
123 break;
124 default:
125 usage();
126 }ARGEND
128 prog = argv;
130 if(argc > 0){
131 name = argv[0];
132 argc--;
133 argv++;
134 }else
135 name = "gnot";
137 threadnotify(nopipes, 1);
138 if((fs = nsmount("acme", "")) == 0)
139 sysfatal("nsmount acme: %r");
140 ctlfd = fsopen(fs, "new/ctl", ORDWR|OCEXEC);
141 if(ctlfd == 0 || fsread(ctlfd, buf, 12) != 12)
142 sysfatal("ctl: %r");
143 id = atoi(buf);
144 sprint(buf, "%d/tag", id);
145 fd = fsopenfd(fs, buf, OWRITE|OCEXEC);
146 write(fd, " Send Delete", 12);
147 close(fd);
148 sprint(buf, "%d/event", id);
149 eventfd = fsopen(fs, buf, ORDWR|OCEXEC);
150 sprint(buf, "%d/addr", id);
151 addrfd = fsopen(fs, buf, ORDWR|OCEXEC);
152 sprint(buf, "%d/data", id);
153 datafd = fsopen(fs, buf, ORDWR|OCEXEC);
154 sprint(buf, "%d/body", id);
155 /* bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC); */
156 if(eventfd==nil || addrfd==nil || datafd==nil)
157 sysfatal("data files: %r");
158 /*
159 if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0)
160 sysfatal("data files: %r");
161 */
162 fsunmount(fs);
164 cwait = threadwaitchan();
165 threadcreate(waitthread, nil, STACK);
166 pid = rcstart(argc, argv, &rcfd, nil);
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 void
183 error(char *s)
185 if(s)
186 fprint(2, "win: %s: %r\n", s);
187 else
188 s = "kill";
189 if(pid != -1)
190 postnote(PNGROUP, pid, "hangup");
191 threadexitsall(s);
194 char*
195 onestring(int argc, char **argv)
197 char *p;
198 int i, n;
199 static char buf[1024];
201 if(argc == 0)
202 return "";
203 p = buf;
204 for(i=0; i<argc; i++){
205 n = strlen(argv[i]);
206 if(p+n+1 >= buf+sizeof buf)
207 break;
208 memmove(p, argv[i], n);
209 p += n;
210 *p++ = ' ';
212 p[-1] = 0;
213 return buf;
216 int
217 getec(Fid *efd)
219 static char buf[8192];
220 static char *bufp;
221 static int nbuf;
223 if(nbuf == 0){
224 nbuf = fsread(efd, buf, sizeof buf);
225 if(nbuf <= 0)
226 error(nil);
227 bufp = buf;
229 --nbuf;
230 return *bufp++;
233 int
234 geten(Fid *efd)
236 int n, c;
238 n = 0;
239 while('0'<=(c=getec(efd)) && c<='9')
240 n = n*10+(c-'0');
241 if(c != ' ')
242 error("event number syntax");
243 return n;
246 int
247 geter(Fid *efd, char *buf, int *nb)
249 Rune r;
250 int n;
252 r = getec(efd);
253 buf[0] = r;
254 n = 1;
255 if(r < Runeself)
256 goto Return;
257 while(!fullrune(buf, n))
258 buf[n++] = getec(efd);
259 chartorune(&r, buf);
260 Return:
261 *nb = n;
262 return r;
265 void
266 gete(Fid *efd, Event *e)
268 int i, nb;
270 e->c1 = getec(efd);
271 e->c2 = getec(efd);
272 e->q0 = geten(efd);
273 e->q1 = geten(efd);
274 e->flag = geten(efd);
275 e->nr = geten(efd);
276 if(e->nr > EVENTSIZE)
277 error("event string too long");
278 e->nb = 0;
279 for(i=0; i<e->nr; i++){
280 e->r[i] = geter(efd, e->b+e->nb, &nb);
281 e->nb += nb;
283 e->r[e->nr] = 0;
284 e->b[e->nb] = 0;
285 if(getec(efd) != '\n')
286 error("event syntax 2");
289 int
290 nrunes(char *s, int nb)
292 int i, n;
293 Rune r;
295 n = 0;
296 for(i=0; i<nb; n++)
297 i += chartorune(&r, s+i);
298 return n;
301 void
302 stdinproc(void *v)
304 Fid *cfd = ctlfd;
305 Fid *efd = eventfd;
306 Fid *dfd = datafd;
307 Fid *afd = addrfd;
308 int fd0 = rcfd;
309 Event e, e2, e3, e4;
311 USED(v);
313 for(;;){
314 if(debug)
315 fprint(2, "typing[%d,%d)\n", q.p, q.p+ntyper);
316 gete(efd, &e);
317 if(debug)
318 fprint(2, "msg %c%c q[%d,%d)... ", e.c1, e.c2, e.q0, e.q1);
319 qlock(&q.lk);
320 switch(e.c1){
321 default:
322 Unknown:
323 print("unknown message %c%c\n", e.c1, e.c2);
324 break;
326 case 'E': /* write to body; can't affect us */
327 if(debug)
328 fprint(2, "shift typing %d... ", e.q1-e.q0);
329 q.p += e.q1-e.q0;
330 break;
332 case 'F': /* generated by our actions; ignore */
333 break;
335 case 'K':
336 case 'M':
337 switch(e.c2){
338 case 'I':
339 if(e.q0 < q.p){
340 if(debug)
341 fprint(2, "shift typing %d... ", e.q1-e.q0);
342 q.p += e.q1-e.q0;
344 else if(e.q0 <= q.p+ntyper){
345 if(debug)
346 fprint(2, "type... ");
347 type(&e, fd0, afd, dfd);
349 break;
351 case 'D':
352 q.p -= delete(&e);
353 break;
355 case 'x':
356 case 'X':
357 if(e.flag & 2)
358 gete(efd, &e2);
359 if(e.flag & 8){
360 gete(efd, &e3);
361 gete(efd, &e4);
363 if(e.flag&1 || (e.c2=='x' && e.nr==0 && e2.nr==0)){
364 /* send it straight back */
365 fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
366 break;
368 if(e.q0==e.q1 && (e.flag&2)){
369 e2.flag = e.flag;
370 e = e2;
372 if(e.flag & 8){
373 if(e.q1 != e.q0){
374 sende(&e, fd0, cfd, afd, dfd, 0);
375 sende(&blank, fd0, cfd, afd, dfd, 0);
377 sende(&e3, fd0, cfd, afd, dfd, 1);
378 }else if(e.q1 != e.q0)
379 sende(&e, fd0, cfd, afd, dfd, 1);
380 break;
382 case 'l':
383 case 'L':
384 /* just send it back */
385 if(e.flag & 2)
386 gete(efd, &e2);
387 fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
388 break;
390 case 'd':
391 case 'i':
392 break;
394 default:
395 goto Unknown;
398 qunlock(&q.lk);
402 void
403 stdoutproc(void *v)
405 int fd1 = rcfd;
406 Fid *afd = addrfd;
407 Fid *dfd = datafd;
408 int n, m, w, npart;
409 char *buf, *s, *t;
410 Rune r;
411 char x[16], hold[UTFmax];
413 USED(v);
414 threadnotify(nopipes, 1);
415 buf = malloc(8192+UTFmax+1);
416 npart = 0;
417 for(;;){
418 /* Let typing have a go -- maybe there's a rubout waiting. */
419 yield();
420 n = threadread(fd1, buf+npart, 8192);
421 if(n < 0)
422 error(nil);
423 if(n == 0)
424 continue;
426 /* squash NULs */
427 s = memchr(buf+npart, 0, n);
428 if(s){
429 for(t=s; s<buf+npart+n; s++)
430 if(*t = *s) /* assign = */
431 t++;
432 n = t-(buf+npart);
435 n += npart;
437 /* hold on to final partial rune */
438 npart = 0;
439 while(n>0 && (buf[n-1]&0xC0)){
440 --n;
441 npart++;
442 if((buf[n]&0xC0)!=0x80){
443 if(fullrune(buf+n, npart)){
444 w = chartorune(&r, buf+n);
445 n += w;
446 npart -= w;
448 break;
451 if(n > 0){
452 memmove(hold, buf+n, npart);
453 buf[n] = 0;
454 n = label(buf, n);
455 buf[n] = 0;
456 qlock(&q.lk);
457 m = sprint(x, "#%d", q.p);
458 if(fswrite(afd, x, m) != m)
459 error("stdout writing address");
460 if(fswrite(dfd, buf, n) != n)
461 error("stdout writing body");
462 q.p += nrunes(buf, n);
463 qunlock(&q.lk);
464 memmove(buf, hold, npart);
469 char wdir[256];
470 int
471 label(char *sr, int n)
473 char *sl, *el, *er, *r;
475 er = sr+n;
476 for(r=er-1; r>=sr; r--)
477 if(*r == '\007')
478 break;
479 if(r < sr)
480 return n;
482 el = r+1;
483 if(el-sr > sizeof wdir)
484 sr = el - sizeof wdir;
485 for(sl=el-3; sl>=sr; sl--)
486 if(sl[0]=='\033' && sl[1]==']' && sl[2]==';')
487 break;
488 if(sl < sr)
489 return n;
491 *r = 0;
492 snprint(wdir, sizeof wdir, "name %s/-%s\n0\n", sl+3, name);
493 fswrite(ctlfd, wdir, strlen(wdir));
495 memmove(sl, el, er-el);
496 n -= (el-sl);
497 return n;
500 int
501 delete(Event *e)
503 uint q0, q1;
504 int deltap;
506 q0 = e->q0;
507 q1 = e->q1;
508 if(q1 <= q.p)
509 return e->q1-e->q0;
510 if(q0 >= q.p+ntyper)
511 return 0;
512 deltap = 0;
513 if(q0 < q.p){
514 deltap = q.p-q0;
515 q0 = 0;
516 }else
517 q0 -= q.p;
518 if(q1 > q.p+ntyper)
519 q1 = ntyper;
520 else
521 q1 -= q.p;
522 deltype(q0, q1);
523 return deltap;
526 void
527 addtype(int c, uint p0, char *b, int nb, int nr)
529 int i, w;
530 Rune r;
531 uint p;
532 char *b0;
534 for(i=0; i<nb; i+=w){
535 w = chartorune(&r, b+i);
536 if((r==0x7F||r==3) && c=='K'){
537 write(rcfd, "\x7F", 1);
538 /* toss all typing */
539 q.p += ntyper+nr;
540 ntypebreak = 0;
541 ntypeb = 0;
542 ntyper = 0;
543 /* buglet: more than one delete ignored */
544 return;
546 if(r=='\n' || r==0x04)
547 ntypebreak++;
549 typing = realloc(typing, ntypeb+nb);
550 if(typing == nil)
551 error("realloc");
552 if(p0 == ntyper)
553 memmove(typing+ntypeb, b, nb);
554 else{
555 b0 = typing;
556 for(p=0; p<p0 && b0<typing+ntypeb; p++){
557 w = chartorune(&r, b0+i);
558 b0 += w;
560 if(p != p0)
561 error("typing: findrune");
562 memmove(b0+nb, b0, (typing+ntypeb)-b0);
563 memmove(b0, b, nb);
565 ntypeb += nb;
566 ntyper += nr;
569 void
570 sendtype(int fd0)
572 int i, n, nr;
574 while(ntypebreak){
575 for(i=0; i<ntypeb; i++)
576 if(typing[i]=='\n' || typing[i]==0x04){
577 n = i+1;
578 i++;
579 if(write(fd0, typing, n) != n)
580 error("sending to program");
581 nr = nrunes(typing, i);
582 q.p += nr;
583 ntyper -= nr;
584 ntypeb -= i;
585 memmove(typing, typing+i, ntypeb);
586 ntypebreak--;
587 goto cont2;
589 print("no breakchar\n");
590 ntypebreak = 0;
591 cont2:;
595 void
596 deltype(uint p0, uint p1)
598 int w;
599 uint p, b0, b1;
600 Rune r;
602 /* advance to p0 */
603 b0 = 0;
604 for(p=0; p<p0 && b0<ntypeb; p++){
605 w = chartorune(&r, typing+b0);
606 b0 += w;
608 if(p != p0)
609 error("deltype 1");
610 /* advance to p1 */
611 b1 = b0;
612 for(; p<p1 && b1<ntypeb; p++){
613 w = chartorune(&r, typing+b1);
614 b1 += w;
615 if(r=='\n' || r==0x04)
616 ntypebreak--;
618 if(p != p1)
619 error("deltype 2");
620 memmove(typing+b0, typing+b1, ntypeb-b1);
621 ntypeb -= b1-b0;
622 ntyper -= p1-p0;
625 void
626 type(Event *e, int fd0, Fid *afd, Fid *dfd)
628 int m, n, nr;
629 char buf[128];
631 if(e->nr > 0)
632 addtype(e->c1, e->q0-q.p, e->b, e->nb, e->nr);
633 else{
634 m = e->q0;
635 while(m < e->q1){
636 n = sprint(buf, "#%d", m);
637 fswrite(afd, buf, n);
638 n = fsread(dfd, buf, sizeof buf);
639 nr = nrunes(buf, n);
640 while(m+nr > e->q1){
641 do; while(n>0 && (buf[--n]&0xC0)==0x80);
642 --nr;
644 if(n == 0)
645 break;
646 addtype(e->c1, m-q.p, buf, n, nr);
647 m += nr;
650 sendtype(fd0);
653 void
654 sende(Event *e, int fd0, Fid *cfd, Fid *afd, Fid *dfd, int donl)
656 int l, m, n, nr, lastc, end;
657 char abuf[16], buf[128];
659 end = q.p+ntyper;
660 l = sprint(abuf, "#%d", end);
661 fswrite(afd, abuf, l);
662 if(e->nr > 0){
663 fswrite(dfd, e->b, e->nb);
664 addtype(e->c1, ntyper, e->b, e->nb, e->nr);
665 lastc = e->r[e->nr-1];
666 }else{
667 m = e->q0;
668 lastc = 0;
669 while(m < e->q1){
670 n = sprint(buf, "#%d", m);
671 fswrite(afd, buf, n);
672 n = fsread(dfd, buf, sizeof buf);
673 nr = nrunes(buf, n);
674 while(m+nr > e->q1){
675 do; while(n>0 && (buf[--n]&0xC0)==0x80);
676 --nr;
678 if(n == 0)
679 break;
680 l = sprint(abuf, "#%d", end);
681 fswrite(afd, abuf, l);
682 fswrite(dfd, buf, n);
683 addtype(e->c1, ntyper, buf, n, nr);
684 lastc = buf[n-1];
685 m += nr;
686 end += nr;
689 if(donl && lastc!='\n'){
690 fswrite(dfd, "\n", 1);
691 addtype(e->c1, ntyper, "\n", 1, 1);
693 fswrite(cfd, "dot=addr", 8);
694 sendtype(fd0);