ref: d3da2e1b89f30f404c3d11053680098f1b7bf677
dir: /appl/lib/plumbmsg.b/
implement Plumbmsg; include "sys.m"; sys: Sys; include "plumbmsg.m"; input: ref Sys->FD; port: ref Sys->FD; portname: string; maxdatasize: int; init(doinput: int, rcvport: string, maxdata: int): int { sys = load Sys Sys->PATH; if(!doinput && rcvport == nil) # server, not client return 1; input = sys->open("/chan/plumb.input", Sys->OWRITE); if(input == nil) return -1; if(rcvport == nil) # sending messages but never receiving them return 1; port = sys->open("/chan/plumb."+rcvport, Sys->OREAD); if(port == nil){ input = nil; return -1; } maxdatasize = maxdata; portname = rcvport; msg := ref Msg; msg.src = portname; msg.dst = "plumb"; msg.kind = "text"; msg.data = array of byte "start"; if(msg.send() < 0){ port = nil; input = nil; return -1; } return 1; } shutdown() { msg := ref Msg; msg.src = portname; msg.dst = "plumb"; msg.kind = "text"; msg.data = array of byte "stop"; msg.send(); } Msg.send(msg: self ref Msg): int { hdr := msg.src+"\n"+ msg.dst+"\n"+ msg.dir+"\n"+ msg.kind+"\n"+ msg.attr+"\n"+ string len msg.data+"\n"; ahdr := array of byte hdr; b := array[len ahdr+len msg.data] of byte; b[0:] = ahdr; b[len ahdr:] = msg.data; return sys->write(input, b, len b); } Msg.recv(): ref Msg { b := array[maxdatasize+1000] of byte; n := sys->read(port, b, len b); if(n <= 0) return nil; return Msg.unpack(b[0:n]); } Msg.unpack(b: array of byte): ref Msg { (hdr, data) := unpack(b, 6); if(hdr == nil) return nil; msg := ref Msg; msg.src = hdr[0]; msg.dst = hdr[1]; msg.dir = hdr[2]; msg.kind = hdr[3]; msg.attr = hdr[4]; msg.data = data; return msg; } Msg.pack(msg: self ref Msg): array of byte { hdr := msg.src+"\n"+ msg.dst+"\n"+ msg.dir+"\n"+ msg.kind+"\n"+ msg.attr+"\n"+ string len msg.data+"\n"; ahdr := array of byte hdr; b := array[len ahdr+len msg.data] of byte; b[0:] = ahdr; b[len ahdr:] = msg.data; return b; } # unpack message from array of bytes. last string in message # is number of bytes in data portion of message unpack(b: array of byte, ns: int): (array of string, array of byte) { i := 0; a := array[ns] of string; for(n:=0; n<ns; n++){ (i, a[n]) = unpackstring(b, i); if(i < 0) return (nil, nil); } nb := int a[ns-1]; if((len b)-i != nb){ sys->print("unpack: bad message format: wrong nbytes\n"); return (nil, nil); } # copy data so b can be reused or freed data := array[nb] of byte; data[0:] = b[i:]; return (a, data); } unpackstring(b: array of byte, i: int): (int, string) { starti := i; while(i < len b){ if(b[i] == byte '\n') return (i+1, string b[starti:i]); i++; } return (-1, nil); } string2attrs(s: string): list of ref Attr { (nil, pairs) := sys->tokenize(s, "\t"); if(pairs == nil) return nil; attrs: list of ref Attr; while(pairs != nil){ pair := hd pairs; pairs = tl pairs; a := ref Attr; for(i:=0; i<len pair; i++) if(pair[i] == '='){ a.name = pair[0:i]; if(++i < len pair) a.val = pair[i:]; break; } attrs = a :: attrs; } return attrs; } attrs2string(l: list of ref Attr): string { s := ""; while(l != nil){ a := hd l; l = tl l; if(s == "") s = a.name + "=" + a.val; else s += "\t" + a.name + "=" + a.val; } return s; } lookup(attrs: list of ref Attr, name: string): (int, string) { while(attrs != nil){ a := hd attrs; attrs = tl attrs; if(a.name == name) return (1, a.val); } return (0, nil); }