diff options
Diffstat (limited to 'appl/lib/plumbmsg.b')
| -rw-r--r-- | appl/lib/plumbmsg.b | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/appl/lib/plumbmsg.b b/appl/lib/plumbmsg.b new file mode 100644 index 00000000..ef9928e1 --- /dev/null +++ b/appl/lib/plumbmsg.b @@ -0,0 +1,190 @@ +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); +} |
