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;
133 char *dump;
135 dump = onestring(argc, argv);
137 ARGBEGIN{
138 case 'd':
139 debug = 1;
140 break;
141 case 'n':
142 name = EARGF(usage());
143 break;
144 default:
145 usage();
146 }ARGEND
148 prog = argv;
150 if(name == nil){
151 if(argc > 0)
152 name = argv[0];
153 else{
154 name = sysname();
155 if(name == nil)
156 name = "gnot";
160 notedisable("sys: write on closed pipe");
161 noteenable("sys: child");
162 notify(hangupnote);
164 if((fs = nsmount("acme", "")) == 0)
165 sysfatal("nsmount acme: %r");
166 ctlfd = fsopen(fs, "new/ctl", ORDWR|OCEXEC);
167 if(ctlfd == 0 || fsread(ctlfd, buf, 12) != 12)
168 sysfatal("ctl: %r");
169 id = atoi(buf);
170 snprint(buf, sizeof buf, "%d", id);
171 putenv("winid", buf);
172 sprint(buf, "%d/tag", id);
173 fd = fsopenfd(fs, buf, OWRITE|OCEXEC);
174 write(fd, " Send Delete", 12);
175 close(fd);
176 sprint(buf, "%d/event", id);
177 eventfd = fsopen(fs, buf, ORDWR|OCEXEC);
178 sprint(buf, "%d/addr", id);
179 addrfd = fsopen(fs, buf, ORDWR|OCEXEC);
180 sprint(buf, "%d/data", id);
181 datafd = fsopen(fs, buf, ORDWR|OCEXEC);
182 sprint(buf, "%d/body", id);
183 /* bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC); */
184 if(eventfd==nil || addrfd==nil || datafd==nil)
185 sysfatal("data files: %r");
186 /*
187 if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0)
188 sysfatal("data files: %r");
189 */
190 fsunmount(fs);
192 cwait = threadwaitchan();
193 threadcreate(waitthread, nil, STACK);
194 pid = rcstart(argc, argv, &rcfd, nil);
195 if(pid == -1)
196 sysfatal("exec failed");
198 getwd(buf1, sizeof buf1);
199 sprint(buf, "name %s/-%s\n0\n", buf1, name);
200 fswrite(ctlfd, buf, strlen(buf));
201 sprint(buf, "dumpdir %s/\n", buf1);
202 fswrite(ctlfd, buf, strlen(buf));
203 sprint(buf, "dump %s\n", dump);
204 fswrite(ctlfd, buf, strlen(buf));
206 updatewinsize(25, 80, 0, 0);
207 proccreate(stdoutproc, nil, STACK);
208 stdinproc(nil);
211 void
212 error(char *s, ...)
214 va_list arg;
216 if(s){
217 va_start(arg, s);
218 s = vsmprint(s, arg);
219 va_end(arg);
220 fprint(2, "win: %s: %r\n", s);
222 if(pid != -1)
223 postnote(PNGROUP, pid, "hangup");
224 threadexitsall(s);
227 char*
228 onestring(int argc, char **argv)
230 char *p;
231 int i, n;
232 static char buf[1024];
234 if(argc == 0)
235 return "";
236 p = buf;
237 for(i=0; i<argc; i++){
238 n = strlen(argv[i]);
239 if(p+n+1 >= buf+sizeof buf)
240 break;
241 memmove(p, argv[i], n);
242 p += n;
243 *p++ = ' ';
245 p[-1] = 0;
246 return buf;
249 int
250 getec(CFid *efd)
252 static char buf[8192];
253 static char *bufp;
254 static int nbuf;
256 if(nbuf == 0){
257 nbuf = fsread(efd, buf, sizeof buf);
258 if(nbuf <= 0)
259 error(nil);
260 bufp = buf;
262 --nbuf;
263 return *bufp++;
266 int
267 geten(CFid *efd)
269 int n, c;
271 n = 0;
272 while('0'<=(c=getec(efd)) && c<='9')
273 n = n*10+(c-'0');
274 if(c != ' ')
275 error("event number syntax");
276 return n;
279 int
280 geter(CFid *efd, char *buf, int *nb)
282 Rune r;
283 int n;
285 r = getec(efd);
286 buf[0] = r;
287 n = 1;
288 if(r < Runeself)
289 goto Return;
290 while(!fullrune(buf, n))
291 buf[n++] = getec(efd);
292 chartorune(&r, buf);
293 Return:
294 *nb = n;
295 return r;
298 void
299 gete(CFid *efd, Event *e)
301 int i, nb;
303 e->c1 = getec(efd);
304 e->c2 = getec(efd);
305 e->q0 = geten(efd);
306 e->q1 = geten(efd);
307 e->flag = geten(efd);
308 e->nr = geten(efd);
309 if(e->nr > EVENTSIZE)
310 error("event string too long");
311 e->nb = 0;
312 for(i=0; i<e->nr; i++){
313 e->r[i] = geter(efd, e->b+e->nb, &nb);
314 e->nb += nb;
316 e->r[e->nr] = 0;
317 e->b[e->nb] = 0;
318 if(getec(efd) != '\n')
319 error("event syntax 2");
322 int
323 nrunes(char *s, int nb)
325 int i, n;
326 Rune r;
328 n = 0;
329 for(i=0; i<nb; n++)
330 i += chartorune(&r, s+i);
331 return n;
334 void
335 stdinproc(void *v)
337 CFid *cfd = ctlfd;
338 CFid *efd = eventfd;
339 CFid *dfd = datafd;
340 CFid *afd = addrfd;
341 int fd0 = rcfd;
342 Event e, e2, e3, e4;
344 USED(v);
346 for(;;){
347 if(debug)
348 fprint(2, "typing[%d,%d)\n", q.p, q.p+ntyper);
349 gete(efd, &e);
350 if(debug)
351 fprint(2, "msg %c%c q[%d,%d)... ", e.c1, e.c2, e.q0, e.q1);
352 qlock(&q.lk);
353 switch(e.c1){
354 default:
355 Unknown:
356 print("unknown message %c%c\n", e.c1, e.c2);
357 break;
359 case 'E': /* write to body; can't affect us */
360 if(debug)
361 fprint(2, "shift typing %d... ", e.q1-e.q0);
362 q.p += e.q1-e.q0;
363 break;
365 case 'F': /* generated by our actions; ignore */
366 break;
368 case 'K':
369 case 'M':
370 switch(e.c2){
371 case 'I':
372 if(e.q0 < q.p){
373 if(debug)
374 fprint(2, "shift typing %d... ", e.q1-e.q0);
375 q.p += e.q1-e.q0;
377 else if(e.q0 <= q.p+ntyper){
378 if(debug)
379 fprint(2, "type... ");
380 type(&e, fd0, afd, dfd);
382 break;
384 case 'D':
385 q.p -= delete(&e);
386 break;
388 case 'x':
389 case 'X':
390 if(e.flag & 2)
391 gete(efd, &e2);
392 if(e.flag & 8){
393 gete(efd, &e3);
394 gete(efd, &e4);
396 if(e.flag&1 || (e.c2=='x' && e.nr==0 && e2.nr==0)){
397 /* send it straight back */
398 fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
399 break;
401 if(e.q0==e.q1 && (e.flag&2)){
402 e2.flag = e.flag;
403 e = e2;
405 if(e.flag & 8){
406 if(e.q1 != e.q0){
407 sende(&e, fd0, cfd, afd, dfd, 0);
408 sende(&blank, fd0, cfd, afd, dfd, 0);
410 sende(&e3, fd0, cfd, afd, dfd, 1);
411 }else if(e.q1 != e.q0)
412 sende(&e, fd0, cfd, afd, dfd, 1);
413 break;
415 case 'l':
416 case 'L':
417 /* just send it back */
418 if(e.flag & 2)
419 gete(efd, &e2);
420 fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
421 break;
423 case 'd':
424 case 'i':
425 break;
427 default:
428 goto Unknown;
431 qunlock(&q.lk);
435 void
436 stdoutproc(void *v)
438 int fd1 = rcfd;
439 CFid *afd = addrfd;
440 CFid *dfd = datafd;
441 int n, m, w, npart;
442 char *buf, *s, *t;
443 Rune r;
444 char x[16], hold[UTFmax];
446 USED(v);
447 buf = malloc(8192+UTFmax+1);
448 npart = 0;
449 for(;;){
450 /* Let typing have a go -- maybe there's a rubout waiting. */
451 yield();
452 n = read(fd1, buf+npart, 8192);
453 if(n <= 0)
454 error(nil);
456 /* squash NULs */
457 s = memchr(buf+npart, 0, n);
458 if(s){
459 for(t=s; s<buf+npart+n; s++)
460 if(*t = *s) /* assign = */
461 t++;
462 n = t-(buf+npart);
465 n += npart;
467 /* hold on to final partial rune */
468 npart = 0;
469 while(n>0 && (buf[n-1]&0xC0)){
470 --n;
471 npart++;
472 if((buf[n]&0xC0)!=0x80){
473 if(fullrune(buf+n, npart)){
474 w = chartorune(&r, buf+n);
475 n += w;
476 npart -= w;
478 break;
481 if(n > 0){
482 memmove(hold, buf+n, npart);
483 buf[n] = 0;
484 n = label(buf, n);
485 buf[n] = 0;
486 qlock(&q.lk);
487 m = sprint(x, "#%d", q.p);
488 if(fswrite(afd, x, m) != m){
489 fprint(2, "stdout writing address: %r; resetting\n");
490 fswrite(afd, "$", 1);
491 m = fsread(afd, x, sizeof x-1);
492 if(m >= 0){
493 x[m] = 0;
494 q.p = atoi(x);
497 if(fswrite(dfd, buf, n) != n)
498 error("stdout writing body");
499 q.p += nrunes(buf, n);
500 qunlock(&q.lk);
501 memmove(buf, hold, npart);
506 char wdir[512];
507 int
508 label(char *sr, int n)
510 char *sl, *el, *er, *r, *p;
512 er = sr+n;
513 for(r=er-1; r>=sr; r--)
514 if(*r == '\007')
515 break;
516 if(r < sr)
517 return n;
519 el = r+1;
520 if(el-sr > sizeof wdir - strlen(name) - 20)
521 sr = el - sizeof wdir - strlen(name) - 20;
522 for(sl=el-3; sl>=sr; sl--)
523 if(sl[0]=='\033' && sl[1]==']' && sl[2]==';')
524 break;
525 if(sl < sr)
526 return n;
528 *r = 0;
529 /*
530 * add /-sysname if not present
531 */
532 snprint(wdir, sizeof wdir, "name %s", sl+3);
533 p = strrchr(wdir, '/');
534 if(p==nil || *(p+1) != '-'){
535 p = wdir+strlen(wdir);
536 if(*(p-1) != '/')
537 *p++ = '/';
538 *p++ = '-';
539 strcpy(p, name);
541 strcat(wdir, "\n0\n");
542 fswrite(ctlfd, wdir, strlen(wdir));
544 memmove(sl, el, er-el);
545 n -= (el-sl);
546 return n;
549 int
550 delete(Event *e)
552 uint q0, q1;
553 int deltap;
555 q0 = e->q0;
556 q1 = e->q1;
557 if(q1 <= q.p)
558 return e->q1-e->q0;
559 if(q0 >= q.p+ntyper)
560 return 0;
561 deltap = 0;
562 if(q0 < q.p){
563 deltap = q.p-q0;
564 q0 = 0;
565 }else
566 q0 -= q.p;
567 if(q1 > q.p+ntyper)
568 q1 = ntyper;
569 else
570 q1 -= q.p;
571 deltype(q0, q1);
572 return deltap;
575 void
576 addtype(int c, uint p0, char *b, int nb, int nr)
578 int i, w;
579 Rune r;
580 uint p;
581 char *b0;
583 for(i=0; i<nb; i+=w){
584 w = chartorune(&r, b+i);
585 if((r==0x7F||r==3) && c=='K'){
586 write(rcfd, "\x7F", 1);
587 /* toss all typing */
588 q.p += ntyper+nr;
589 ntypebreak = 0;
590 ntypeb = 0;
591 ntyper = 0;
592 /* buglet: more than one delete ignored */
593 return;
595 if(r=='\n' || r==0x04)
596 ntypebreak++;
598 typing = realloc(typing, ntypeb+nb);
599 if(typing == nil)
600 error("realloc");
601 if(p0 == ntyper)
602 memmove(typing+ntypeb, b, nb);
603 else{
604 b0 = typing;
605 for(p=0; p<p0 && b0<typing+ntypeb; p++){
606 w = chartorune(&r, b0+i);
607 b0 += w;
609 if(p != p0)
610 error("typing: findrune");
611 memmove(b0+nb, b0, (typing+ntypeb)-b0);
612 memmove(b0, b, nb);
614 ntypeb += nb;
615 ntyper += nr;
618 void
619 sendtype(int fd0)
621 int i, n, nr;
623 while(ntypebreak){
624 for(i=0; i<ntypeb; i++)
625 if(typing[i]=='\n' || typing[i]==0x04){
626 n = i+1;
627 i++;
628 if(write(fd0, typing, n) != n)
629 error("sending to program");
630 nr = nrunes(typing, i);
631 q.p += nr;
632 ntyper -= nr;
633 ntypeb -= i;
634 memmove(typing, typing+i, ntypeb);
635 ntypebreak--;
636 goto cont2;
638 print("no breakchar\n");
639 ntypebreak = 0;
640 cont2:;
644 void
645 deltype(uint p0, uint p1)
647 int w;
648 uint p, b0, b1;
649 Rune r;
651 /* advance to p0 */
652 b0 = 0;
653 for(p=0; p<p0 && b0<ntypeb; p++){
654 w = chartorune(&r, typing+b0);
655 b0 += w;
657 if(p != p0)
658 error("deltype 1");
659 /* advance to p1 */
660 b1 = b0;
661 for(; p<p1 && b1<ntypeb; p++){
662 w = chartorune(&r, typing+b1);
663 b1 += w;
664 if(r=='\n' || r==0x04)
665 ntypebreak--;
667 if(p != p1)
668 error("deltype 2");
669 memmove(typing+b0, typing+b1, ntypeb-b1);
670 ntypeb -= b1-b0;
671 ntyper -= p1-p0;
674 void
675 type(Event *e, int fd0, CFid *afd, CFid *dfd)
677 int m, n, nr;
678 char buf[128];
680 if(e->nr > 0)
681 addtype(e->c1, e->q0-q.p, e->b, e->nb, e->nr);
682 else{
683 m = e->q0;
684 while(m < e->q1){
685 n = sprint(buf, "#%d", m);
686 fswrite(afd, buf, n);
687 n = fsread(dfd, buf, sizeof buf);
688 nr = nrunes(buf, n);
689 while(m+nr > e->q1){
690 do; while(n>0 && (buf[--n]&0xC0)==0x80);
691 --nr;
693 if(n == 0)
694 break;
695 addtype(e->c1, m-q.p, buf, n, nr);
696 m += nr;
699 sendtype(fd0);
702 void
703 sende(Event *e, int fd0, CFid *cfd, CFid *afd, CFid *dfd, int donl)
705 int l, m, n, nr, lastc, end;
706 char abuf[16], buf[128];
708 end = q.p+ntyper;
709 l = sprint(abuf, "#%d", end);
710 fswrite(afd, abuf, l);
711 if(e->nr > 0){
712 fswrite(dfd, e->b, e->nb);
713 addtype(e->c1, ntyper, e->b, e->nb, e->nr);
714 lastc = e->r[e->nr-1];
715 }else{
716 m = e->q0;
717 lastc = 0;
718 while(m < e->q1){
719 n = sprint(buf, "#%d", m);
720 fswrite(afd, buf, n);
721 n = fsread(dfd, buf, sizeof buf);
722 nr = nrunes(buf, n);
723 while(m+nr > e->q1){
724 do; while(n>0 && (buf[--n]&0xC0)==0x80);
725 --nr;
727 if(n == 0)
728 break;
729 l = sprint(abuf, "#%d", end);
730 fswrite(afd, abuf, l);
731 fswrite(dfd, buf, n);
732 addtype(e->c1, ntyper, buf, n, nr);
733 lastc = buf[n-1];
734 m += nr;
735 end += nr;
738 if(donl && lastc!='\n'){
739 fswrite(dfd, "\n", 1);
740 addtype(e->c1, ntyper, "\n", 1, 1);
742 fswrite(cfd, "dot=addr", 8);
743 sendtype(fd0);