implement Plumbing; include "sys.m"; sys: Sys; fprint, sprint: import sys; include "draw.m"; include "arg.m"; arg: Arg; include "error.m"; err: Error; checkload, stderr, error, kill: import err; include "sh.m"; sh: Sh; Context: import sh; include "plumbmsg.m"; plumbmsg: Plumbmsg; Msg: import plumbmsg; Plumbing: module { init: fn(nil: ref Draw->Context, argv: list of string); }; verbose := 0; plumbing(rc: chan of string, dctx: ref Draw->Context, port: string, argv: list of string) { sys->pctl(Sys->FORKFD, nil); ctxt := Context.new(dctx); if (plumbmsg->init(0, port, 512) < 0){ rc <-= sprint("plumbinit: %r"); raise "fail: plumb"; } # make sure the shell command is parsed only once. cmd := sh->stringlist2list(argv); if((hd argv) != nil && (hd argv)[0] == '{'){ (c, e) := sh->parse(hd argv); if(c == nil){ rc <-= e; raise "fail: " + e; } cmd = ref Sh->Listnode(c, hd argv) :: tl cmd; } rc <-= nil; for (;;) { m := Msg.recv(); if (m == nil) break; if (m.kind != "text"){ fprint(stderr, "plumbing: non-text message\n"); continue; } val := list of {ref Sh->Listnode(nil, string m.data)}; if (verbose) fprint(stderr, "plumbing: %s: %s\n", port, string m.data); ctxt.set("msg", val); ctxt.run(cmd, 0); m = nil; val = nil; } error("plumbing: can't read plumb port"); } init(dctx: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; err = load Error Error->PATH; err->init(); sh = checkload(load Sh Sh->PATH, Sh->PATH); plumbmsg = checkload(load Plumbmsg Plumbmsg->PATH, Plumbmsg->PATH); arg = checkload(load Arg Arg->PATH, Arg->PATH); arg->init(argv); arg->setusage("plumbing [-v] port cmd [arg...]"); while ((opt := arg->opt()) != 0) { case opt { 'v' => verbose = 1; * => arg->usage(); } } argv = arg->argv(); if (len argv < 2) arg->usage(); c := chan of string; spawn plumbing(c, dctx, hd argv, tl argv); e := <- c; if (e != nil) error(e); }