ref: 8204f3beedf0fb9a46a8062e217057d2c068158d
dir: /cmd.c/
#include <u.h> #include <libc.h> #include <thread.h> #include "dat.h" #include "fns.h" extern Channel *pidc; Dot dot; int bound = 1; static int epfd[2]; static int setright(char *s) { vlong off, m; off = atoll(s) * Sampsz; if(dot.cur > off){ m = Rate * Sampsz; setjump(off - m >= 0 ? off - m : 0); } return setloop(off); } static int setleft(char *s) { vlong off; off = atoll(s) * Sampsz; if(dot.cur < off) setjump(off + Sampsz); return setloop(off); } static int jumpto(char *s) { return setjump(atoll(s) * Sampsz); } static int paste(char *) { int r; qlock(&lsync); r = cpaste(&dot) == 0 ? 1 : -1; qunlock(&lsync); return r; } static int copy(char *) { ccopy(&dot); return 0; } static int cut(char *) { dprint(nil, "cmd/cut %Δ\n", &dot); if(dot.from == 0 && dot.to == dot.totalsz){ werrstr("cut: can't cut entire buffer"); return -1; } qlock(&lsync); ccut(&dot); qunlock(&lsync); return 1; } static int crop(char *) { dprint(nil, "cmd/crop %Δ\n", &dot); qlock(&lsync); ccrop(&dot); qunlock(&lsync); return 1; } static int writebuf(int fd) { int nio; uchar *b; usize n, m, k; Dot d; d = dot; d.cur = d.from; if((nio = iounit(fd)) == 0) nio = 8192; for(m=d.to-d.from, b=(uchar*)&d; m>0; m-=n, d.cur+=n){ k = nio < m ? nio : m; if((b = getslice(&d, k, &k)) == nil || k <= 0){ fprint(2, "writebuf: couldn\'t snarf: %r\n"); return -1; } if((n = write(fd, b, k)) != k){ fprint(2, "writebuf: short write not %zd: %r\n", k); return -1; } } write(fd, b, 0); /* close pipe */ return 0; } static void rc(void *s) { close(epfd[1]); dup(epfd[0], 0); dup(epfd[0], 1); close(epfd[0]); procexecl(pidc, "/bin/rc", "rc", "-c", s, nil); sysfatal("procexec: %r"); } static void wproc(void *efd) { int fd; fd = (intptr)efd; writebuf(fd); close(fd); threadexits(nil); } static void rproc(void *efd) { int fd; Dot d, cd; Chunk *c; d = dot; if(d.from != 0 && d.to != d.totalsz) d.off = -1; fd = (intptr)efd; if((c = loadfile(fd, &cd)) == nil){ fprint(2, "failed reading from pipe: %r"); threadexits("read error"); } close(fd); qlock(&lsync); chold(c, &d); dot = d; qunlock(&lsync); if(paste(nil) < 0) fprint(2, "paste: %r\n"); redraw(1); threadexits(nil); } static int pipeline(char *arg, int rr, int wr) { if(nslots == 0){ fprint(2, "pipeline: too many backgrounded processes\n"); return -1; } if(rr) reader = 0; if(pipe(epfd) < 0) sysfatal("pipe: %r"); if(procrfork(rc, arg, mainstacksize, RFFDG|RFNOTEG|RFNAMEG) < 0) sysfatal("procrfork: %r"); close(epfd[0]); if(wr && procrfork(wproc, (int*)dup(epfd[1], -1), mainstacksize, RFFDG|RFNOTEG|RFNAMEG) < 0){ fprint(2, "procrfork: %r\n"); return -1; } if(rr && procrfork(rproc, (int*)dup(epfd[1], -1), mainstacksize, RFFDG) < 0){ fprint(2, "procrfork: %r\n"); return -1; } close(epfd[1]); return 0; } static int pipeto(char *arg) { return pipeline(arg, 0, 1); } static int pipefrom(char *arg) { return pipeline(arg, 1, 0); } static int pipethrough(char *arg) { return pipeline(arg, 1, 1); } static int pipeselflessly(char *arg) { return pipeline(arg, 0, 0); } static int replicate(char *) { static char u[256]; snprint(u, sizeof u, "<[3=0] window -m %s /fd/3", argv0); return pipeto(u); } static int readfrom(char *s) { int fd; if((fd = open(s, OREAD)) < 0) return -1; if(procrfork(rproc, (int*)fd, mainstacksize, RFFDG) < 0){ fprint(2, "procrfork: %r\n"); return -1; } return 0; } /* the entire string is treated as the filename, ie. spaces * and any other weird characters will be part of it */ static int writeto(char *arg) { int fd; if((fd = create(arg, OWRITE, 0664)) < 0){ werrstr("writeto: %r"); return -1; } if(procrfork(wproc, (int*)fd, mainstacksize, RFFDG|RFNOTEG|RFNAMEG) < 0){ fprint(2, "procrfork: %r\n"); return -1; } close(fd); return 0; } int cmd(char *s) { int n, x; int (*fn)(char*); Rune r, r´; assert(s != nil); s += chartorune(&r, s); for(;;){ n = chartorune(&r´, s); if(r´ == Runeerror){ werrstr("malformed input"); return -1; } if(r´ == 0 || r´ != ' ' && r´ != '\t') break; s += n; } dprint(dot.norris, "current dot=%Δ\n", &dot); if(reader >= 0){ switch(r){ case '<': case '^': case 'c': case 'd': //case 'm': case 'p': case 'r': case 'U': case 'u': case 'w': case 'x': werrstr("still reading from external process\n"); return -1; } } x = 666; fn = nil; switch(r){ case 'q': threadexitsall(nil); case 'D': killreader(); break; case '<': fn = pipefrom; break; case '^': fn = pipethrough; break; case '|': fn = pipeto; break; case '!': fn = pipeselflessly; break; case 'L': fn = setleft; break; case 'R': fn = setright; break; case 'c': fn = copy; break; case 'd': fn = cut; break; case 'j': fn = jumpto; break; //case 'm': fn = mark; break; case 'p': fn = paste; break; case 'r': fn = readfrom; break; case 's': fn = replicate; break; case 'U': fn = unpop; break; case 'u': fn = popop; break; case 'w': fn = writeto; break; case 'x': fn = crop; break; default: werrstr("unknown command %C", r); return -1; } if(fn != nil){ x = fn(s); dprint(dot.norris, "final dot=%Δ\n", &dot); } return x; } static void advanceone(Dot *d, usize n) { usize m; if(d->cur < d->from || d->cur >= d->to) d->cur = d->from; while(n > 0){ m = d->to - d->cur > n ? n : d->to - d->cur; n -= m; d->cur += m; if(d->cur == d->to) d->cur = d->from; } } void advance(usize n) { advanceone(&dot, n); }