Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <fcall.h>
5 #include <9pclient.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 CFid *eventfd;
47 CFid *addrfd;
48 CFid *datafd;
49 CFid *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, CFid*, CFid*);
70 void sende(Event*, int, CFid*, CFid*, CFid*, int);
71 char *onestring(int, char**);
72 int delete(Event*);
73 void deltype(uint, uint);
74 void runproc(void*);
76 int
77 fsfidprint(CFid *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 hangupnote(void *a, char *msg)
115 if(strcmp(msg, "hangup") == 0 && pid != 0){
116 postnote(PNGROUP, pid, "hangup");
117 noted(NDFLT);
119 if(strstr(msg, "child")){
120 /* bug: do better */
121 threadexitsall(0);
123 noted(NDFLT);
126 void
127 threadmain(int argc, char **argv)
129 int fd, id;
130 char buf[256];
131 char buf1[128];
132 CFsys *fs;
134 ARGBEGIN{
135 case 'd':
136 debug = 1;
137 break;
138 case 'n':
139 name = EARGF(usage());
140 break;
141 default:
142 usage();
143 }ARGEND
145 prog = argv;
147 if(name == nil){
148 if(argc > 0)
149 name = argv[0];
150 else{
151 name = sysname();
152 if(name == nil)
153 name = "gnot";
157 notedisable("sys: write on closed pipe");
158 noteenable("sys: child");
159 notify(hangupnote);
161 if((fs = nsmount("acme", "")) == 0)
162 sysfatal("nsmount acme: %r");
163 ctlfd = fsopen(fs, "new/ctl", ORDWR|OCEXEC);
164 if(ctlfd == 0 || fsread(ctlfd, buf, 12) != 12)
165 sysfatal("ctl: %r");
166 id = atoi(buf);
167 snprint(buf, sizeof buf, "%d", id);
168 putenv("winid", buf);
169 sprint(buf, "%d/tag", id);
170 fd = fsopenfd(fs, buf, OWRITE|OCEXEC);
171 write(fd, " Send Delete", 12);
172 close(fd);
173 sprint(buf, "%d/event", id);
174 eventfd = fsopen(fs, buf, ORDWR|OCEXEC);
175 sprint(buf, "%d/addr", id);
176 addrfd = fsopen(fs, buf, ORDWR|OCEXEC);
177 sprint(buf, "%d/data", id);
178 datafd = fsopen(fs, buf, ORDWR|OCEXEC);
179 sprint(buf, "%d/body", id);
180 /* bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC); */
181 if(eventfd==nil || addrfd==nil || datafd==nil)
182 sysfatal("data files: %r");
183 /*
184 if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0)
185 sysfatal("data files: %r");
186 */
187 fsunmount(fs);
189 cwait = threadwaitchan();
190 threadcreate(waitthread, nil, STACK);
191 pid = rcstart(argc, argv, &rcfd, nil);
192 if(pid == -1)
193 sysfatal("exec failed");
195 getwd(buf1, sizeof buf1);
196 sprint(buf, "name %s/-%s\n0\n", buf1, name);
197 fswrite(ctlfd, buf, strlen(buf));
198 sprint(buf, "dumpdir %s/\n", buf1);
199 fswrite(ctlfd, buf, strlen(buf));
200 sprint(buf, "dump %s\n", onestring(argc, argv));
201 fswrite(ctlfd, buf, strlen(buf));
203 updatewinsize(25, 80, 0, 0);
204 proccreate(stdoutproc, nil, STACK);
205 stdinproc(nil);
208 void
209 error(char *s)
211 if(s)
212 fprint(2, "win: %s: %r\n", s);
213 else
214 s = "kill";
215 if(pid != -1)
216 postnote(PNGROUP, pid, "hangup");
217 threadexitsall(s);
220 char*
221 onestring(int argc, char **argv)
223 char *p;
224 int i, n;
225 static char buf[1024];
227 if(argc == 0)
228 return "";
229 p = buf;
230 for(i=0; i<argc; i++){
231 n = strlen(argv[i]);
232 if(p+n+1 >= buf+sizeof buf)
233 break;
234 memmove(p, argv[i], n);
235 p += n;
236 *p++ = ' ';
238 p[-1] = 0;
239 return buf;
242 int
243 getec(CFid *efd)
245 static char buf[8192];
246 static char *bufp;
247 static int nbuf;
249 if(nbuf == 0){
250 nbuf = fsread(efd, buf, sizeof buf);
251 if(nbuf <= 0)
252 error(nil);
253 bufp = buf;
255 --nbuf;
256 return *bufp++;
259 int
260 geten(CFid *efd)
262 int n, c;
264 n = 0;
265 while('0'<=(c=getec(efd)) && c<='9')
266 n = n*10+(c-'0');
267 if(c != ' ')
268 error("event number syntax");
269 return n;
272 int
273 geter(CFid *efd, char *buf, int *nb)
275 Rune r;
276 int n;
278 r = getec(efd);
279 buf[0] = r;
280 n = 1;
281 if(r < Runeself)
282 goto Return;
283 while(!fullrune(buf, n))
284 buf[n++] = getec(efd);
285 chartorune(&r, buf);
286 Return:
287 *nb = n;
288 return r;
291 void
292 gete(CFid *efd, Event *e)
294 int i, nb;
296 e->c1 = getec(efd);
297 e->c2 = getec(efd);
298 e->q0 = geten(efd);
299 e->q1 = geten(efd);
300 e->flag = geten(efd);
301 e->nr = geten(efd);
302 if(e->nr > EVENTSIZE)
303 error("event string too long");
304 e->nb = 0;
305 for(i=0; i<e->nr; i++){
306 e->r[i] = geter(efd, e->b+e->nb, &nb);
307 e->nb += nb;
309 e->r[e->nr] = 0;
310 e->b[e->nb] = 0;
311 if(getec(efd) != '\n')
312 error("event syntax 2");
315 int
316 nrunes(char *s, int nb)
318 int i, n;
319 Rune r;
321 n = 0;
322 for(i=0; i<nb; n++)
323 i += chartorune(&r, s+i);
324 return n;
327 void
328 stdinproc(void *v)
330 CFid *cfd = ctlfd;
331 CFid *efd = eventfd;
332 CFid *dfd = datafd;
333 CFid *afd = addrfd;
334 int fd0 = rcfd;
335 Event e, e2, e3, e4;
337 USED(v);
339 for(;;){
340 if(debug)
341 fprint(2, "typing[%d,%d)\n", q.p, q.p+ntyper);
342 gete(efd, &e);
343 if(debug)
344 fprint(2, "msg %c%c q[%d,%d)... ", e.c1, e.c2, e.q0, e.q1);
345 qlock(&q.lk);
346 switch(e.c1){
347 default:
348 Unknown:
349 print("unknown message %c%c\n", e.c1, e.c2);
350 break;
352 case 'E': /* write to body; can't affect us */
353 if(debug)
354 fprint(2, "shift typing %d... ", e.q1-e.q0);
355 q.p += e.q1-e.q0;
356 break;
358 case 'F': /* generated by our actions; ignore */
359 break;
361 case 'K':
362 case 'M':
363 switch(e.c2){
364 case 'I':
365 if(e.q0 < q.p){
366 if(debug)
367 fprint(2, "shift typing %d... ", e.q1-e.q0);
368 q.p += e.q1-e.q0;
370 else if(e.q0 <= q.p+ntyper){
371 if(debug)
372 fprint(2, "type... ");
373 type(&e, fd0, afd, dfd);
375 break;
377 case 'D':
378 q.p -= delete(&e);
379 break;
381 case 'x':
382 case 'X':
383 if(e.flag & 2)
384 gete(efd, &e2);
385 if(e.flag & 8){
386 gete(efd, &e3);
387 gete(efd, &e4);
389 if(e.flag&1 || (e.c2=='x' && e.nr==0 && e2.nr==0)){
390 /* send it straight back */
391 fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
392 break;
394 if(e.q0==e.q1 && (e.flag&2)){
395 e2.flag = e.flag;
396 e = e2;
398 if(e.flag & 8){
399 if(e.q1 != e.q0){
400 sende(&e, fd0, cfd, afd, dfd, 0);
401 sende(&blank, fd0, cfd, afd, dfd, 0);
403 sende(&e3, fd0, cfd, afd, dfd, 1);
404 }else if(e.q1 != e.q0)
405 sende(&e, fd0, cfd, afd, dfd, 1);
406 break;
408 case 'l':
409 case 'L':
410 /* just send it back */
411 if(e.flag & 2)
412 gete(efd, &e2);
413 fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
414 break;
416 case 'd':
417 case 'i':
418 break;
420 default:
421 goto Unknown;
424 qunlock(&q.lk);
428 void
429 stdoutproc(void *v)
431 int fd1 = rcfd;
432 CFid *afd = addrfd;
433 CFid *dfd = datafd;
434 int n, m, w, npart;
435 char *buf, *s, *t;
436 Rune r;
437 char x[16], hold[UTFmax];
439 USED(v);
440 buf = malloc(8192+UTFmax+1);
441 npart = 0;
442 for(;;){
443 /* Let typing have a go -- maybe there's a rubout waiting. */
444 yield();
445 n = read(fd1, buf+npart, 8192);
446 if(n <= 0)
447 error(nil);
449 /* squash NULs */
450 s = memchr(buf+npart, 0, n);
451 if(s){
452 for(t=s; s<buf+npart+n; s++)
453 if(*t = *s) /* assign = */
454 t++;
455 n = t-(buf+npart);
458 n += npart;
460 /* hold on to final partial rune */
461 npart = 0;
462 while(n>0 && (buf[n-1]&0xC0)){
463 --n;
464 npart++;
465 if((buf[n]&0xC0)!=0x80){
466 if(fullrune(buf+n, npart)){
467 w = chartorune(&r, buf+n);
468 n += w;
469 npart -= w;
471 break;
474 if(n > 0){
475 memmove(hold, buf+n, npart);
476 buf[n] = 0;
477 n = label(buf, n);
478 buf[n] = 0;
479 qlock(&q.lk);
480 m = sprint(x, "#%d", q.p);
481 if(fswrite(afd, x, m) != m)
482 error("stdout writing address");
483 if(fswrite(dfd, buf, n) != n)
484 error("stdout writing body");
485 q.p += nrunes(buf, n);
486 qunlock(&q.lk);
487 memmove(buf, hold, npart);
492 char wdir[512];
493 int
494 label(char *sr, int n)
496 char *sl, *el, *er, *r, *p;
498 er = sr+n;
499 for(r=er-1; r>=sr; r--)
500 if(*r == '\007')
501 break;
502 if(r < sr)
503 return n;
505 el = r+1;
506 if(el-sr > sizeof wdir - strlen(name) - 20)
507 sr = el - sizeof wdir - strlen(name) - 20;
508 for(sl=el-3; sl>=sr; sl--)
509 if(sl[0]=='\033' && sl[1]==']' && sl[2]==';')
510 break;
511 if(sl < sr)
512 return n;
514 *r = 0;
515 /*
516 * add /-sysname if not present
517 */
518 snprint(wdir, sizeof wdir, "name %s", sl+3);
519 p = strrchr(wdir, '/');
520 if(p==nil || *(p+1) != '-'){
521 p = wdir+strlen(wdir);
522 if(*(p-1) != '/')
523 *p++ = '/';
524 *p++ = '-';
525 strcpy(p, name);
527 strcat(wdir, "\n0\n");
528 fswrite(ctlfd, wdir, strlen(wdir));
530 memmove(sl, el, er-el);
531 n -= (el-sl);
532 return n;
535 int
536 delete(Event *e)
538 uint q0, q1;
539 int deltap;
541 q0 = e->q0;
542 q1 = e->q1;
543 if(q1 <= q.p)
544 return e->q1-e->q0;
545 if(q0 >= q.p+ntyper)
546 return 0;
547 deltap = 0;
548 if(q0 < q.p){
549 deltap = q.p-q0;
550 q0 = 0;
551 }else
552 q0 -= q.p;
553 if(q1 > q.p+ntyper)
554 q1 = ntyper;
555 else
556 q1 -= q.p;
557 deltype(q0, q1);
558 return deltap;
561 void
562 addtype(int c, uint p0, char *b, int nb, int nr)
564 int i, w;
565 Rune r;
566 uint p;
567 char *b0;
569 for(i=0; i<nb; i+=w){
570 w = chartorune(&r, b+i);
571 if((r==0x7F||r==3) && c=='K'){
572 write(rcfd, "\x7F", 1);
573 /* toss all typing */
574 q.p += ntyper+nr;
575 ntypebreak = 0;
576 ntypeb = 0;
577 ntyper = 0;
578 /* buglet: more than one delete ignored */
579 return;
581 if(r=='\n' || r==0x04)
582 ntypebreak++;
584 typing = realloc(typing, ntypeb+nb);
585 if(typing == nil)
586 error("realloc");
587 if(p0 == ntyper)
588 memmove(typing+ntypeb, b, nb);
589 else{
590 b0 = typing;
591 for(p=0; p<p0 && b0<typing+ntypeb; p++){
592 w = chartorune(&r, b0+i);
593 b0 += w;
595 if(p != p0)
596 error("typing: findrune");
597 memmove(b0+nb, b0, (typing+ntypeb)-b0);
598 memmove(b0, b, nb);
600 ntypeb += nb;
601 ntyper += nr;
604 void
605 sendtype(int fd0)
607 int i, n, nr;
609 while(ntypebreak){
610 for(i=0; i<ntypeb; i++)
611 if(typing[i]=='\n' || typing[i]==0x04){
612 n = i+1;
613 i++;
614 if(write(fd0, typing, n) != n)
615 error("sending to program");
616 nr = nrunes(typing, i);
617 q.p += nr;
618 ntyper -= nr;
619 ntypeb -= i;
620 memmove(typing, typing+i, ntypeb);
621 ntypebreak--;
622 goto cont2;
624 print("no breakchar\n");
625 ntypebreak = 0;
626 cont2:;
630 void
631 deltype(uint p0, uint p1)
633 int w;
634 uint p, b0, b1;
635 Rune r;
637 /* advance to p0 */
638 b0 = 0;
639 for(p=0; p<p0 && b0<ntypeb; p++){
640 w = chartorune(&r, typing+b0);
641 b0 += w;
643 if(p != p0)
644 error("deltype 1");
645 /* advance to p1 */
646 b1 = b0;
647 for(; p<p1 && b1<ntypeb; p++){
648 w = chartorune(&r, typing+b1);
649 b1 += w;
650 if(r=='\n' || r==0x04)
651 ntypebreak--;
653 if(p != p1)
654 error("deltype 2");
655 memmove(typing+b0, typing+b1, ntypeb-b1);
656 ntypeb -= b1-b0;
657 ntyper -= p1-p0;
660 void
661 type(Event *e, int fd0, CFid *afd, CFid *dfd)
663 int m, n, nr;
664 char buf[128];
666 if(e->nr > 0)
667 addtype(e->c1, e->q0-q.p, e->b, e->nb, e->nr);
668 else{
669 m = e->q0;
670 while(m < e->q1){
671 n = sprint(buf, "#%d", m);
672 fswrite(afd, buf, n);
673 n = fsread(dfd, buf, sizeof buf);
674 nr = nrunes(buf, n);
675 while(m+nr > e->q1){
676 do; while(n>0 && (buf[--n]&0xC0)==0x80);
677 --nr;
679 if(n == 0)
680 break;
681 addtype(e->c1, m-q.p, buf, n, nr);
682 m += nr;
685 sendtype(fd0);
688 void
689 sende(Event *e, int fd0, CFid *cfd, CFid *afd, CFid *dfd, int donl)
691 int l, m, n, nr, lastc, end;
692 char abuf[16], buf[128];
694 end = q.p+ntyper;
695 l = sprint(abuf, "#%d", end);
696 fswrite(afd, abuf, l);
697 if(e->nr > 0){
698 fswrite(dfd, e->b, e->nb);
699 addtype(e->c1, ntyper, e->b, e->nb, e->nr);
700 lastc = e->r[e->nr-1];
701 }else{
702 m = e->q0;
703 lastc = 0;
704 while(m < e->q1){
705 n = sprint(buf, "#%d", m);
706 fswrite(afd, buf, n);
707 n = fsread(dfd, buf, sizeof buf);
708 nr = nrunes(buf, n);
709 while(m+nr > e->q1){
710 do; while(n>0 && (buf[--n]&0xC0)==0x80);
711 --nr;
713 if(n == 0)
714 break;
715 l = sprint(abuf, "#%d", end);
716 fswrite(afd, abuf, l);
717 fswrite(dfd, buf, n);
718 addtype(e->c1, ntyper, buf, n, nr);
719 lastc = buf[n-1];
720 m += nr;
721 end += nr;
724 if(donl && lastc!='\n'){
725 fswrite(dfd, "\n", 1);
726 addtype(e->c1, ntyper, "\n", 1, 1);
728 fswrite(cfd, "dot=addr", 8);
729 sendtype(fd0);