ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/lib/slip.b/
implement Filter;
include "sys.m";
include "filter.m";
End: con byte 8r300;
Esc: con byte 8r333;
Eend: con byte 8r334; # encoded End byte
Eesc: con byte 8r335; # encoded Esc byte
init()
{
}
start(param: string): chan of ref Rq
{
req := chan of ref Rq;
if(param == "encode")
spawn encode(req);
else
spawn decode(req);
return req;
}
encode(reqs: chan of ref Rq)
{
sys := load Sys Sys->PATH;
reqs <-= ref Rq.Start(sys->pctl(0, nil));
buf := array[8192] of byte;
rc := chan of int;
do{
reqs <-= ref Rq.Fill(buf, rc);
if((n := <-rc) <= 0){
if(n == 0)
reqs <-= ref Rq.Finished(nil);
break;
}
b := array[2*n + 2] of byte; # optimise time not space
o := 1;
b[0] = End;
for(i := 0; i < n; i++){
if((c := buf[i]) == End || c == Esc){
b[o++] = Esc;
c = byte (Eend + (c& byte 1));
}
b[o++] = c;
}
b[o++] = End;
if(o != len b)
b = b[0:o];
reqs <-= ref Rq.Result(b, rc);
}while(<-rc != -1);
}
Slipesc, Slipend: con (1<<8) + iota;
Slipsize: con 1006; # rfc's suggestion
slipin(c: byte, esc: int): int
{
if(esc == Slipesc){ # last byte was Esc
if(c == Eend)
c = End;
else if(c == Eesc)
c = Esc;
}else{
if(c == Esc)
return Slipesc;
if(c == End)
return Slipend;
}
return int c;
}
decode(reqs: chan of ref Rq)
{
sys := load Sys Sys->PATH;
reqs <-= ref Rq.Start(sys->pctl(0, nil));
buf := array[8192] of byte;
b := array[Slipsize] of byte;
rc := chan of int;
c := 0;
o := 0;
for(;;){
reqs <-= ref Rq.Fill(buf, rc);
if((n := <-rc) <= 0){
if(n < 0)
exit;
break;
}
for(i := 0; i < n; i++){
c = slipin(buf[i], c);
if(c == Slipend){
if(o != 0){
reqs <-= ref Rq.Result(b[0:o], rc);
if(<-rc == -1)
exit;
b = array[Slipsize] of byte;
o = 0;
}
}else if(c != Slipesc){
if(o >= len b){
t := array[3*len b/2] of byte;
t[0:] = b;
b = t;
}
b[o++] = byte c;
}
}
}
# partial block discarded
reqs <-= ref Rq.Finished(nil);
}