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 case 'n':
125 name = EARGF(usage());
126 break;
127 default:
128 usage();
129 }ARGEND
131 prog = argv;
133 if(name == nil){
134 if(argc > 0)
135 name = argv[0];
136 else{
137 name = sysname();
138 if(name == nil)
139 name = "gnot";
143 threadnotify(nopipes, 1);
144 if((fs = nsmount("acme", "")) == 0)
145 sysfatal("nsmount acme: %r");
146 ctlfd = fsopen(fs, "new/ctl", ORDWR|OCEXEC);
147 if(ctlfd == 0 || fsread(ctlfd, buf, 12) != 12)
148 sysfatal("ctl: %r");
149 id = atoi(buf);
150 snprint(buf, sizeof buf, "%d", id);
151 putenv("winid", buf);
152 sprint(buf, "%d/tag", id);
153 fd = fsopenfd(fs, buf, OWRITE|OCEXEC);
154 write(fd, " Send Delete", 12);
155 close(fd);
156 sprint(buf, "%d/event", id);
157 eventfd = fsopen(fs, buf, ORDWR|OCEXEC);
158 sprint(buf, "%d/addr", id);
159 addrfd = fsopen(fs, buf, ORDWR|OCEXEC);
160 sprint(buf, "%d/data", id);
161 datafd = fsopen(fs, buf, ORDWR|OCEXEC);
162 sprint(buf, "%d/body", id);
163 /* bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC); */
164 if(eventfd==nil || addrfd==nil || datafd==nil)
165 sysfatal("data files: %r");
166 /*
167 if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0)
168 sysfatal("data files: %r");
169 */
170 fsunmount(fs);
172 cwait = threadwaitchan();
173 threadcreate(waitthread, nil, STACK);
174 pid = rcstart(argc, argv, &rcfd, nil);
175 if(pid == -1)
176 sysfatal("exec failed");
178 getwd(buf1, sizeof buf1);
179 sprint(buf, "name %s/-%s\n0\n", buf1, name);
180 fswrite(ctlfd, buf, strlen(buf));
181 sprint(buf, "dumpdir %s/\n", buf1);
182 fswrite(ctlfd, buf, strlen(buf));
183 sprint(buf, "dump %s\n", onestring(argc, argv));
184 fswrite(ctlfd, buf, strlen(buf));
186 updatewinsize(25, 80, 0, 0);
187 threadcreate(stdoutproc, nil, STACK);
188 stdinproc(nil);
191 void
192 error(char *s)
194 if(s)
195 fprint(2, "win: %s: %r\n", s);
196 else
197 s = "kill";
198 if(pid != -1)
199 postnote(PNGROUP, pid, "hangup");
200 threadexitsall(s);
203 char*
204 onestring(int argc, char **argv)
206 char *p;
207 int i, n;
208 static char buf[1024];
210 if(argc == 0)
211 return "";
212 p = buf;
213 for(i=0; i<argc; i++){
214 n = strlen(argv[i]);
215 if(p+n+1 >= buf+sizeof buf)
216 break;
217 memmove(p, argv[i], n);
218 p += n;
219 *p++ = ' ';
221 p[-1] = 0;
222 return buf;
225 int
226 getec(Fid *efd)
228 static char buf[8192];
229 static char *bufp;
230 static int nbuf;
232 if(nbuf == 0){
233 nbuf = fsread(efd, buf, sizeof buf);
234 if(nbuf <= 0)
235 error(nil);
236 bufp = buf;
238 --nbuf;
239 return *bufp++;
242 int
243 geten(Fid *efd)
245 int n, c;
247 n = 0;
248 while('0'<=(c=getec(efd)) && c<='9')
249 n = n*10+(c-'0');
250 if(c != ' ')
251 error("event number syntax");
252 return n;
255 int
256 geter(Fid *efd, char *buf, int *nb)
258 Rune r;
259 int n;
261 r = getec(efd);
262 buf[0] = r;
263 n = 1;
264 if(r < Runeself)
265 goto Return;
266 while(!fullrune(buf, n))
267 buf[n++] = getec(efd);
268 chartorune(&r, buf);
269 Return:
270 *nb = n;
271 return r;
274 void
275 gete(Fid *efd, Event *e)
277 int i, nb;
279 e->c1 = getec(efd);
280 e->c2 = getec(efd);
281 e->q0 = geten(efd);
282 e->q1 = geten(efd);
283 e->flag = geten(efd);
284 e->nr = geten(efd);
285 if(e->nr > EVENTSIZE)
286 error("event string too long");
287 e->nb = 0;
288 for(i=0; i<e->nr; i++){
289 e->r[i] = geter(efd, e->b+e->nb, &nb);
290 e->nb += nb;
292 e->r[e->nr] = 0;
293 e->b[e->nb] = 0;
294 if(getec(efd) != '\n')
295 error("event syntax 2");
298 int
299 nrunes(char *s, int nb)
301 int i, n;
302 Rune r;
304 n = 0;
305 for(i=0; i<nb; n++)
306 i += chartorune(&r, s+i);
307 return n;
310 void
311 stdinproc(void *v)
313 Fid *cfd = ctlfd;
314 Fid *efd = eventfd;
315 Fid *dfd = datafd;
316 Fid *afd = addrfd;
317 int fd0 = rcfd;
318 Event e, e2, e3, e4;
320 USED(v);
322 for(;;){
323 if(debug)
324 fprint(2, "typing[%d,%d)\n", q.p, q.p+ntyper);
325 gete(efd, &e);
326 if(debug)
327 fprint(2, "msg %c%c q[%d,%d)... ", e.c1, e.c2, e.q0, e.q1);
328 qlock(&q.lk);
329 switch(e.c1){
330 default:
331 Unknown:
332 print("unknown message %c%c\n", e.c1, e.c2);
333 break;
335 case 'E': /* write to body; can't affect us */
336 if(debug)
337 fprint(2, "shift typing %d... ", e.q1-e.q0);
338 q.p += e.q1-e.q0;
339 break;
341 case 'F': /* generated by our actions; ignore */
342 break;
344 case 'K':
345 case 'M':
346 switch(e.c2){
347 case 'I':
348 if(e.q0 < q.p){
349 if(debug)
350 fprint(2, "shift typing %d... ", e.q1-e.q0);
351 q.p += e.q1-e.q0;
353 else if(e.q0 <= q.p+ntyper){
354 if(debug)
355 fprint(2, "type... ");
356 type(&e, fd0, afd, dfd);
358 break;
360 case 'D':
361 q.p -= delete(&e);
362 break;
364 case 'x':
365 case 'X':
366 if(e.flag & 2)
367 gete(efd, &e2);
368 if(e.flag & 8){
369 gete(efd, &e3);
370 gete(efd, &e4);
372 if(e.flag&1 || (e.c2=='x' && e.nr==0 && e2.nr==0)){
373 /* send it straight back */
374 fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
375 break;
377 if(e.q0==e.q1 && (e.flag&2)){
378 e2.flag = e.flag;
379 e = e2;
381 if(e.flag & 8){
382 if(e.q1 != e.q0){
383 sende(&e, fd0, cfd, afd, dfd, 0);
384 sende(&blank, fd0, cfd, afd, dfd, 0);
386 sende(&e3, fd0, cfd, afd, dfd, 1);
387 }else if(e.q1 != e.q0)
388 sende(&e, fd0, cfd, afd, dfd, 1);
389 break;
391 case 'l':
392 case 'L':
393 /* just send it back */
394 if(e.flag & 2)
395 gete(efd, &e2);
396 fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
397 break;
399 case 'd':
400 case 'i':
401 break;
403 default:
404 goto Unknown;
407 qunlock(&q.lk);
411 void
412 stdoutproc(void *v)
414 int fd1 = rcfd;
415 Fid *afd = addrfd;
416 Fid *dfd = datafd;
417 int n, m, w, npart;
418 char *buf, *s, *t;
419 Rune r;
420 char x[16], hold[UTFmax];
422 USED(v);
423 threadnotify(nopipes, 1);
424 buf = malloc(8192+UTFmax+1);
425 npart = 0;
426 for(;;){
427 /* Let typing have a go -- maybe there's a rubout waiting. */
428 yield();
429 n = threadread(fd1, buf+npart, 8192);
430 if(n < 0)
431 error(nil);
432 if(n == 0)
433 continue;
435 /* squash NULs */
436 s = memchr(buf+npart, 0, n);
437 if(s){
438 for(t=s; s<buf+npart+n; s++)
439 if(*t = *s) /* assign = */
440 t++;
441 n = t-(buf+npart);
444 n += npart;
446 /* hold on to final partial rune */
447 npart = 0;
448 while(n>0 && (buf[n-1]&0xC0)){
449 --n;
450 npart++;
451 if((buf[n]&0xC0)!=0x80){
452 if(fullrune(buf+n, npart)){
453 w = chartorune(&r, buf+n);
454 n += w;
455 npart -= w;
457 break;
460 if(n > 0){
461 memmove(hold, buf+n, npart);
462 buf[n] = 0;
463 n = label(buf, n);
464 buf[n] = 0;
465 qlock(&q.lk);
466 m = sprint(x, "#%d", q.p);
467 if(fswrite(afd, x, m) != m)
468 error("stdout writing address");
469 if(fswrite(dfd, buf, n) != n)
470 error("stdout writing body");
471 q.p += nrunes(buf, n);
472 qunlock(&q.lk);
473 memmove(buf, hold, npart);
478 char wdir[256];
479 int
480 label(char *sr, int n)
482 char *sl, *el, *er, *r;
484 er = sr+n;
485 for(r=er-1; r>=sr; r--)
486 if(*r == '\007')
487 break;
488 if(r < sr)
489 return n;
491 el = r+1;
492 if(el-sr > sizeof wdir)
493 sr = el - sizeof wdir;
494 for(sl=el-3; sl>=sr; sl--)
495 if(sl[0]=='\033' && sl[1]==']' && sl[2]==';')
496 break;
497 if(sl < sr)
498 return n;
500 *r = 0;
501 snprint(wdir, sizeof wdir, "name %s/-%s\n0\n", sl+3, name);
502 fswrite(ctlfd, wdir, strlen(wdir));
504 memmove(sl, el, er-el);
505 n -= (el-sl);
506 return n;
509 int
510 delete(Event *e)
512 uint q0, q1;
513 int deltap;
515 q0 = e->q0;
516 q1 = e->q1;
517 if(q1 <= q.p)
518 return e->q1-e->q0;
519 if(q0 >= q.p+ntyper)
520 return 0;
521 deltap = 0;
522 if(q0 < q.p){
523 deltap = q.p-q0;
524 q0 = 0;
525 }else
526 q0 -= q.p;
527 if(q1 > q.p+ntyper)
528 q1 = ntyper;
529 else
530 q1 -= q.p;
531 deltype(q0, q1);
532 return deltap;
535 void
536 addtype(int c, uint p0, char *b, int nb, int nr)
538 int i, w;
539 Rune r;
540 uint p;
541 char *b0;
543 for(i=0; i<nb; i+=w){
544 w = chartorune(&r, b+i);
545 if((r==0x7F||r==3) && c=='K'){
546 write(rcfd, "\x7F", 1);
547 /* toss all typing */
548 q.p += ntyper+nr;
549 ntypebreak = 0;
550 ntypeb = 0;
551 ntyper = 0;
552 /* buglet: more than one delete ignored */
553 return;
555 if(r=='\n' || r==0x04)
556 ntypebreak++;
558 typing = realloc(typing, ntypeb+nb);
559 if(typing == nil)
560 error("realloc");
561 if(p0 == ntyper)
562 memmove(typing+ntypeb, b, nb);
563 else{
564 b0 = typing;
565 for(p=0; p<p0 && b0<typing+ntypeb; p++){
566 w = chartorune(&r, b0+i);
567 b0 += w;
569 if(p != p0)
570 error("typing: findrune");
571 memmove(b0+nb, b0, (typing+ntypeb)-b0);
572 memmove(b0, b, nb);
574 ntypeb += nb;
575 ntyper += nr;
578 void
579 sendtype(int fd0)
581 int i, n, nr;
583 while(ntypebreak){
584 for(i=0; i<ntypeb; i++)
585 if(typing[i]=='\n' || typing[i]==0x04){
586 n = i+1;
587 i++;
588 if(write(fd0, typing, n) != n)
589 error("sending to program");
590 nr = nrunes(typing, i);
591 q.p += nr;
592 ntyper -= nr;
593 ntypeb -= i;
594 memmove(typing, typing+i, ntypeb);
595 ntypebreak--;
596 goto cont2;
598 print("no breakchar\n");
599 ntypebreak = 0;
600 cont2:;
604 void
605 deltype(uint p0, uint p1)
607 int w;
608 uint p, b0, b1;
609 Rune r;
611 /* advance to p0 */
612 b0 = 0;
613 for(p=0; p<p0 && b0<ntypeb; p++){
614 w = chartorune(&r, typing+b0);
615 b0 += w;
617 if(p != p0)
618 error("deltype 1");
619 /* advance to p1 */
620 b1 = b0;
621 for(; p<p1 && b1<ntypeb; p++){
622 w = chartorune(&r, typing+b1);
623 b1 += w;
624 if(r=='\n' || r==0x04)
625 ntypebreak--;
627 if(p != p1)
628 error("deltype 2");
629 memmove(typing+b0, typing+b1, ntypeb-b1);
630 ntypeb -= b1-b0;
631 ntyper -= p1-p0;
634 void
635 type(Event *e, int fd0, Fid *afd, Fid *dfd)
637 int m, n, nr;
638 char buf[128];
640 if(e->nr > 0)
641 addtype(e->c1, e->q0-q.p, e->b, e->nb, e->nr);
642 else{
643 m = e->q0;
644 while(m < e->q1){
645 n = sprint(buf, "#%d", m);
646 fswrite(afd, buf, n);
647 n = fsread(dfd, buf, sizeof buf);
648 nr = nrunes(buf, n);
649 while(m+nr > e->q1){
650 do; while(n>0 && (buf[--n]&0xC0)==0x80);
651 --nr;
653 if(n == 0)
654 break;
655 addtype(e->c1, m-q.p, buf, n, nr);
656 m += nr;
659 sendtype(fd0);
662 void
663 sende(Event *e, int fd0, Fid *cfd, Fid *afd, Fid *dfd, int donl)
665 int l, m, n, nr, lastc, end;
666 char abuf[16], buf[128];
668 end = q.p+ntyper;
669 l = sprint(abuf, "#%d", end);
670 fswrite(afd, abuf, l);
671 if(e->nr > 0){
672 fswrite(dfd, e->b, e->nb);
673 addtype(e->c1, ntyper, e->b, e->nb, e->nr);
674 lastc = e->r[e->nr-1];
675 }else{
676 m = e->q0;
677 lastc = 0;
678 while(m < e->q1){
679 n = sprint(buf, "#%d", m);
680 fswrite(afd, buf, n);
681 n = fsread(dfd, buf, sizeof buf);
682 nr = nrunes(buf, n);
683 while(m+nr > e->q1){
684 do; while(n>0 && (buf[--n]&0xC0)==0x80);
685 --nr;
687 if(n == 0)
688 break;
689 l = sprint(abuf, "#%d", end);
690 fswrite(afd, abuf, l);
691 fswrite(dfd, buf, n);
692 addtype(e->c1, ntyper, buf, n, nr);
693 lastc = buf[n-1];
694 m += nr;
695 end += nr;
698 if(donl && lastc!='\n'){
699 fswrite(dfd, "\n", 1);
700 addtype(e->c1, ntyper, "\n", 1, 1);
702 fswrite(cfd, "dot=addr", 8);
703 sendtype(fd0);