1implement Plumb; 2 3include "sys.m"; 4 sys: Sys; 5 6include "draw.m"; 7 8include "arg.m"; 9 10include "plumbmsg.m"; 11 plumbmsg: Plumbmsg; 12 Msg, Attr: import plumbmsg; 13 14include "workdir.m"; 15 workdir: Workdir; 16 17Plumb: module 18{ 19 init: fn(nil: ref Draw->Context, nil: list of string); 20}; 21 22init(nil: ref Draw->Context, args: list of string) 23{ 24 sys = load Sys Sys->PATH; 25 plumbmsg = load Plumbmsg Plumbmsg->PATH; 26 if(plumbmsg == nil) 27 nomod(Plumbmsg->PATH); 28 workdir = load Workdir Workdir->PATH; 29 if(workdir == nil) 30 nomod(Workdir->PATH); 31 32 if(plumbmsg->init(1, nil, 0) < 0) 33 err(sys->sprint("can't connect to plumb: %r")); 34 35 attrs: list of ref Attr; 36 input := 0; 37 m := ref Msg("plumb", nil, workdir->init(), "text", nil, nil); 38 arg := load Arg Arg->PATH; 39 arg->init(args); 40 arg->setusage("plumb [-s src] [-d dest] [-w wdir] [-t type] [-a name val] -i | ... data ..."); 41 while((c := arg->opt()) != 0) 42 case c { 43 's' => 44 m.src = arg->earg(); 45 'd' => 46 m.dst = arg->earg(); 47 'w' or 'D' => 48 m.dir = arg->earg(); 49 'i' => 50 input++; 51 't' or 'k'=> 52 m.kind = arg->arg(); 53 'a' => 54 name := arg->earg(); 55 val := arg->earg(); 56 attrs = tack(attrs, ref Attr(name, val)); 57 * => 58 arg->usage(); 59 } 60 args = arg->argv(); 61 if(input && args != nil || !input && args == nil) 62 arg->usage(); 63 arg = nil; 64 65 if(input){ 66 m.data = gather(sys->fildes(0)); 67 (notfound, nil) := plumbmsg->lookup(plumbmsg->string2attrs(m.attr), "action"); 68 if(notfound) 69 tack(attrs, ref Attr("action", "showdata")); 70 m.attr = plumbmsg->attrs2string(attrs); 71 if(m.send() < 0) 72 err(sys->sprint("can't send message: %r")); 73 exit; 74 } 75 76 nb := 0; 77 for(a := args; a != nil; a = tl a) 78 nb += len array of byte hd a; 79 nb += len args; 80 buf := array[nb] of byte; 81 nb = 0; 82 for(a = args; a != nil; a = tl a){ 83 b := array of byte hd a; 84 buf[nb++] = byte ' '; 85 buf[nb:] = b; 86 nb += len b; 87 } 88 m.data = buf[1:]; 89 m.attr = plumbmsg->attrs2string(attrs); 90 if(m.send() < 0) 91 err(sys->sprint("can't plumb message: %r")); 92} 93 94gather(fd: ref Sys->FD): array of byte 95{ 96 Chunk: con 8192; # arbitrary 97 ndata := 0; 98 buf := array[Chunk] of byte; 99 while((n := sys->read(fd, buf[ndata:], len buf - ndata)) > 0){ 100 ndata += n; 101 if(len buf - ndata < Chunk){ 102 t := array[len buf+Chunk] of byte; 103 t[0:] = buf[0: ndata]; 104 buf = t; 105 } 106 } 107 if(n < 0) 108 err(sys->sprint("error reading input: %r")); 109 return buf[0: ndata]; 110} 111 112tack(l: list of ref Attr, v: ref Attr): list of ref Attr 113{ 114 if(l == nil) 115 return v :: nil; 116 return hd l :: tack(tl l, v); 117} 118 119nomod(m: string) 120{ 121 err(sys->sprint("can't load %s: %r", m)); 122} 123 124err(s: string) 125{ 126 sys->fprint(sys->fildes(2), "plumb: %s\n", s); 127 raise "fail:error"; 128} 129