Blob
1 #include <u.h>2 #include <libc.h>3 #include <thread.h>4 #include <fcall.h>5 #include <fs.h>7 #define EVENTSIZE 2568 #define STACK 3276810 typedef struct Event Event;11 typedef struct Q Q;13 struct Event14 {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 Q35 {36 QLock lk;37 int p;38 int k;39 };41 Q q;43 int eventfd;44 int addrfd;45 int datafd;46 int ctlfd;47 int bodyfd;49 char *typing;50 int ntypeb;51 int ntyper;52 int ntypebreak;53 int debug;55 char **prog;56 int p[2];57 Channel *cpid;58 int pid = -1;60 void error(char*);61 void stdinproc(void*);62 void stdoutproc(void*);63 void type(Event*, int, int, int);64 void sende(Event*, int, int, int, int, int);65 char *onestring(int, char**);66 int delete(Event*);67 void deltype(uint, uint);68 void runproc(void*);70 void71 usage(void)72 {73 fprint(2, "usage: win cmd args...\n");74 threadexitsall("usage");75 }77 int78 nopipes(void *v, char *msg)79 {80 USED(v);81 if(strcmp(msg, "sys: write on closed pipe") == 0)82 return 1;83 return 0;84 }86 void87 threadmain(int argc, char **argv)88 {89 int fd, id;90 char buf[256];91 char buf1[128];92 char *name;93 Fsys *fs;95 ARGBEGIN{96 case 'd':97 debug = 1;98 break;99 default:100 usage();101 }ARGEND103 prog = argv;105 if(argc > 0)106 name = argv[0];107 else108 name = "gnot";110 threadnotify(nopipes, 1);111 if((fs = nsmount("acme", "")) < 0)112 sysfatal("nsmount acme: %r");113 ctlfd = fsopenfd(fs, "new/ctl", ORDWR|OCEXEC);114 if(ctlfd < 0 || read(ctlfd, buf, 12) != 12)115 sysfatal("ctl: %r");116 id = atoi(buf);117 sprint(buf, "%d/tag", id);118 fd = fsopenfd(fs, buf, OWRITE|OCEXEC);119 write(fd, " Send Delete", 12);120 close(fd);121 sprint(buf, "%d/event", id);122 eventfd = fsopenfd(fs, buf, ORDWR|OCEXEC);123 sprint(buf, "%d/addr", id);124 addrfd = fsopenfd(fs, buf, ORDWR|OCEXEC);125 sprint(buf, "%d/data", id);126 datafd = fsopenfd(fs, buf, ORDWR|OCEXEC);127 sprint(buf, "%d/body", id);128 bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC);129 if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0)130 sysfatal("data files: %r");131 fsunmount(fs);133 if(pipe(p) < 0)134 sysfatal("pipe: %r");136 cpid = chancreate(sizeof(ulong), 1);137 threadcreate(runproc, nil, STACK);138 pid = recvul(cpid);139 if(pid == -1)140 sysfatal("exec failed");142 getwd(buf1, sizeof buf1);143 sprint(buf, "name %s/-%s\n0\n", buf1, name);144 write(ctlfd, buf, strlen(buf));145 sprint(buf, "dumpdir %s/\n", buf1);146 write(ctlfd, buf, strlen(buf));147 sprint(buf, "dump %s\n", onestring(argc, argv));148 write(ctlfd, buf, strlen(buf));150 // proccreate(stdoutproc, nil, STACK);151 stdinproc(nil);152 }154 char *shell[] = { "rc", "-i", 0 };155 void156 runproc(void *v)157 {158 int fd[3];159 char *sh;161 USED(v);163 fd[0] = p[1];164 fd[1] = bodyfd;165 fd[2] = bodyfd;166 // fd[1] = p[1];167 // fd[2] = p[1];169 if(prog[0] == nil){170 prog = shell;171 if((sh = getenv("SHELL")) != nil)172 shell[0] = sh;173 }174 threadexec(cpid, fd, prog[0], prog);175 threadexits(nil);176 }178 void179 error(char *s)180 {181 if(s)182 fprint(2, "win: %s: %r\n", s);183 else184 s = "kill";185 if(pid != -1)186 postnote(PNGROUP, pid, "hangup");187 threadexitsall(s);188 }190 char*191 onestring(int argc, char **argv)192 {193 char *p;194 int i, n;195 static char buf[1024];197 if(argc == 0)198 return "";199 p = buf;200 for(i=0; i<argc; i++){201 n = strlen(argv[i]);202 if(p+n+1 >= buf+sizeof buf)203 break;204 memmove(p, argv[i], n);205 p += n;206 *p++ = ' ';207 }208 p[-1] = 0;209 return buf;210 }212 int213 getec(int efd)214 {215 static char buf[8192];216 static char *bufp;217 static int nbuf;219 if(nbuf == 0){220 nbuf = read(efd, buf, sizeof buf);221 if(nbuf <= 0)222 error(nil);223 bufp = buf;224 }225 --nbuf;226 return *bufp++;227 }229 int230 geten(int efd)231 {232 int n, c;234 n = 0;235 while('0'<=(c=getec(efd)) && c<='9')236 n = n*10+(c-'0');237 if(c != ' ')238 error("event number syntax");239 return n;240 }242 int243 geter(int efd, char *buf, int *nb)244 {245 Rune r;246 int n;248 r = getec(efd);249 buf[0] = r;250 n = 1;251 if(r < Runeself)252 goto Return;253 while(!fullrune(buf, n))254 buf[n++] = getec(efd);255 chartorune(&r, buf);256 Return:257 *nb = n;258 return r;259 }261 void262 gete(int efd, Event *e)263 {264 int i, nb;266 e->c1 = getec(efd);267 e->c2 = getec(efd);268 e->q0 = geten(efd);269 e->q1 = geten(efd);270 e->flag = geten(efd);271 e->nr = geten(efd);272 if(e->nr > EVENTSIZE)273 error("event string too long");274 e->nb = 0;275 for(i=0; i<e->nr; i++){276 e->r[i] = geter(efd, e->b+e->nb, &nb);277 e->nb += nb;278 }279 e->r[e->nr] = 0;280 e->b[e->nb] = 0;281 if(getec(efd) != '\n')282 error("event syntax 2");283 }285 int286 nrunes(char *s, int nb)287 {288 int i, n;289 Rune r;291 n = 0;292 for(i=0; i<nb; n++)293 i += chartorune(&r, s+i);294 return n;295 }297 void298 stdinproc(void *v)299 {300 int cfd = ctlfd;301 int efd = eventfd;302 int dfd = datafd;303 int afd = addrfd;304 int fd0 = p[0];305 Event e, e2, e3, e4;307 USED(v);309 for(;;){310 if(debug)311 fprint(2, "typing[%d,%d)\n", q.p, q.p+ntyper);312 gete(efd, &e);313 if(debug)314 fprint(2, "msg %c%c q[%d,%d)... ", e.c1, e.c2, e.q0, e.q1);315 qlock(&q.lk);316 switch(e.c1){317 default:318 Unknown:319 print("unknown message %c%c\n", e.c1, e.c2);320 break;322 case 'E': /* write to body; can't affect us */323 if(debug)324 fprint(2, "shift typing %d... ", e.q1-e.q0);325 q.p += e.q1-e.q0;326 break;328 case 'F': /* generated by our actions; ignore */329 break;331 case 'K':332 case 'M':333 switch(e.c2){334 case 'I':335 if(e.q0 < q.p){336 if(debug)337 fprint(2, "shift typing %d... ", e.q1-e.q0);338 q.p += e.q1-e.q0;339 }340 else if(e.q0 <= q.p+ntyper){341 if(debug)342 fprint(2, "type... ");343 type(&e, fd0, afd, dfd);344 }345 break;347 case 'D':348 q.p -= delete(&e);349 break;351 case 'x':352 case 'X':353 if(e.flag & 2)354 gete(efd, &e2);355 if(e.flag & 8){356 gete(efd, &e3);357 gete(efd, &e4);358 }359 if(e.flag&1 || (e.c2=='x' && e.nr==0 && e2.nr==0)){360 /* send it straight back */361 fprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);362 break;363 }364 if(e.q0==e.q1 && (e.flag&2)){365 e2.flag = e.flag;366 e = e2;367 }368 if(e.flag & 8){369 if(e.q1 != e.q0){370 sende(&e, fd0, cfd, afd, dfd, 0);371 sende(&blank, fd0, cfd, afd, dfd, 0);372 }373 sende(&e3, fd0, cfd, afd, dfd, 1);374 }else if(e.q1 != e.q0)375 sende(&e, fd0, cfd, afd, dfd, 1);376 break;378 case 'l':379 case 'L':380 /* just send it back */381 if(e.flag & 2)382 gete(efd, &e2);383 fprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);384 break;386 case 'd':387 case 'i':388 break;390 default:391 goto Unknown;392 }393 }394 qunlock(&q.lk);395 }396 }398 void399 stdoutproc(void *v)400 {401 int fd1 = p[0];402 int afd = addrfd;403 int dfd = datafd;404 int n, m, w, npart;405 char *buf, *s, *t;406 Rune r;407 char x[16], hold[UTFmax];409 USED(v);410 threadnotify(nopipes, 1);411 buf = malloc(8192+UTFmax+1);412 npart = 0;413 for(;;){414 n = read(fd1, buf+npart, 8192);415 if(n < 0)416 error(nil);417 if(n == 0)418 continue;420 /* squash NULs */421 s = memchr(buf+npart, 0, n);422 if(s){423 for(t=s; s<buf+npart+n; s++)424 if(*t = *s) /* assign = */425 t++;426 n = t-(buf+npart);427 }429 n += npart;431 /* hold on to final partial rune */432 npart = 0;433 while(n>0 && (buf[n-1]&0xC0)){434 --n;435 npart++;436 if((buf[n]&0xC0)!=0x80){437 if(fullrune(buf+n, npart)){438 w = chartorune(&r, buf+n);439 n += w;440 npart -= w;441 }442 break;443 }444 }445 if(n > 0){446 memmove(hold, buf+n, npart);447 buf[n] = 0;448 qlock(&q.lk);449 m = sprint(x, "#%d", q.p);450 if(write(afd, x, m) != m)451 error("stdout writing address");452 if(write(dfd, buf, n) != n)453 error("stdout writing body");454 q.p += nrunes(buf, n);455 qunlock(&q.lk);456 memmove(buf, hold, npart);457 }458 }459 }461 int462 delete(Event *e)463 {464 uint q0, q1;465 int deltap;467 q0 = e->q0;468 q1 = e->q1;469 if(q1 <= q.p)470 return e->q1-e->q0;471 if(q0 >= q.p+ntyper)472 return 0;473 deltap = 0;474 if(q0 < q.p){475 deltap = q.p-q0;476 q0 = 0;477 }else478 q0 -= q.p;479 if(q1 > q.p+ntyper)480 q1 = ntyper;481 else482 q1 -= q.p;483 deltype(q0, q1);484 return deltap;485 }487 void488 addtype(int c, uint p0, char *b, int nb, int nr)489 {490 int i, w;491 Rune r;492 uint p;493 char *b0;495 for(i=0; i<nb; i+=w){496 w = chartorune(&r, b+i);497 if((r==0x7F||r==3) && c=='K'){498 postnote(PNGROUP, pid, "interrupt");499 /* toss all typing */500 q.p += ntyper+nr;501 ntypebreak = 0;502 ntypeb = 0;503 ntyper = 0;504 /* buglet: more than one delete ignored */505 return;506 }507 if(r=='\n' || r==0x04)508 ntypebreak++;509 }510 typing = realloc(typing, ntypeb+nb);511 if(typing == nil)512 error("realloc");513 if(p0 == ntyper)514 memmove(typing+ntypeb, b, nb);515 else{516 b0 = typing;517 for(p=0; p<p0 && b0<typing+ntypeb; p++){518 w = chartorune(&r, b0+i);519 b0 += w;520 }521 if(p != p0)522 error("typing: findrune");523 memmove(b0+nb, b0, (typing+ntypeb)-b0);524 memmove(b0, b, nb);525 }526 ntypeb += nb;527 ntyper += nr;528 }530 void531 sendtype(int fd0)532 {533 int i, n, nr;535 while(ntypebreak){536 for(i=0; i<ntypeb; i++)537 if(typing[i]=='\n' || typing[i]==0x04){538 n = i + (typing[i] == '\n');539 i++;540 if(write(fd0, typing, n) != n)541 error("sending to program");542 nr = nrunes(typing, i);543 q.p += nr;544 ntyper -= nr;545 ntypeb -= i;546 memmove(typing, typing+i, ntypeb);547 ntypebreak--;548 goto cont2;549 }550 print("no breakchar\n");551 ntypebreak = 0;552 cont2:553 }554 }556 void557 deltype(uint p0, uint p1)558 {559 int w;560 uint p, b0, b1;561 Rune r;563 /* advance to p0 */564 b0 = 0;565 for(p=0; p<p0 && b0<ntypeb; p++){566 w = chartorune(&r, typing+b0);567 b0 += w;568 }569 if(p != p0)570 error("deltype 1");571 /* advance to p1 */572 b1 = b0;573 for(; p<p1 && b1<ntypeb; p++){574 w = chartorune(&r, typing+b1);575 b1 += w;576 if(r=='\n' || r==0x04)577 ntypebreak--;578 }579 if(p != p1)580 error("deltype 2");581 memmove(typing+b0, typing+b1, ntypeb-b1);582 ntypeb -= b1-b0;583 ntyper -= p1-p0;584 }586 void587 type(Event *e, int fd0, int afd, int dfd)588 {589 int m, n, nr;590 char buf[128];592 if(e->nr > 0)593 addtype(e->c1, e->q0-q.p, e->b, e->nb, e->nr);594 else{595 m = e->q0;596 while(m < e->q1){597 n = sprint(buf, "#%d", m);598 write(afd, buf, n);599 n = read(dfd, buf, sizeof buf);600 nr = nrunes(buf, n);601 while(m+nr > e->q1){602 do; while(n>0 && (buf[--n]&0xC0)==0x80);603 --nr;604 }605 if(n == 0)606 break;607 addtype(e->c1, m-q.p, buf, n, nr);608 m += nr;609 }610 }611 sendtype(fd0);612 }614 void615 sende(Event *e, int fd0, int cfd, int afd, int dfd, int donl)616 {617 int l, m, n, nr, lastc, end;618 char abuf[16], buf[128];620 end = q.p+ntyper;621 l = sprint(abuf, "#%d", end);622 write(afd, abuf, l);623 if(e->nr > 0){624 write(dfd, e->b, e->nb);625 addtype(e->c1, ntyper, e->b, e->nb, e->nr);626 lastc = e->r[e->nr-1];627 }else{628 m = e->q0;629 lastc = 0;630 while(m < e->q1){631 n = sprint(buf, "#%d", m);632 write(afd, buf, n);633 n = read(dfd, buf, sizeof buf);634 nr = nrunes(buf, n);635 while(m+nr > e->q1){636 do; while(n>0 && (buf[--n]&0xC0)==0x80);637 --nr;638 }639 if(n == 0)640 break;641 l = sprint(abuf, "#%d", end);642 write(afd, abuf, l);643 write(dfd, buf, n);644 addtype(e->c1, ntyper, buf, n, nr);645 lastc = buf[n-1];646 m += nr;647 end += nr;648 }649 }650 if(donl && lastc!='\n'){651 write(dfd, "\n", 1);652 addtype(e->c1, ntyper, "\n", 1, 1);653 }654 write(cfd, "dot=addr", 8);655 sendtype(fd0);656 }