summaryrefslogtreecommitdiff
path: root/appl/lib/slip.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/lib/slip.b')
-rw-r--r--appl/lib/slip.b113
1 files changed, 113 insertions, 0 deletions
diff --git a/appl/lib/slip.b b/appl/lib/slip.b
new file mode 100644
index 00000000..da904015
--- /dev/null
+++ b/appl/lib/slip.b
@@ -0,0 +1,113 @@
+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);
+}