xref: /inferno-os/appl/lib/slip.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement Filter;
2
3include "sys.m";
4
5include "filter.m";
6
7End: con byte 8r300;
8Esc: con byte 8r333;
9Eend: con byte 8r334;	# encoded End byte
10Eesc: con byte 8r335;	# encoded Esc byte
11
12init()
13{
14}
15
16start(param: string): chan of ref Rq
17{
18	req := chan of ref Rq;
19	if(param == "encode")
20		spawn encode(req);
21	else
22		spawn decode(req);
23	return req;
24}
25
26encode(reqs: chan of ref Rq)
27{
28	sys := load Sys Sys->PATH;
29	reqs <-= ref Rq.Start(sys->pctl(0, nil));
30	buf := array[8192] of byte;
31	rc := chan of int;
32	do{
33		reqs <-= ref Rq.Fill(buf, rc);
34		if((n := <-rc) <= 0){
35			if(n == 0)
36				reqs <-= ref Rq.Finished(nil);
37			break;
38		}
39		b := array[2*n + 2] of byte;	# optimise time not space
40		o := 1;
41		b[0] = End;
42		for(i := 0; i < n; i++){
43			if((c := buf[i]) == End || c == Esc){
44				b[o++] = Esc;
45				c = byte (Eend + (c& byte 1));
46			}
47			b[o++] = c;
48		}
49		b[o++] = End;
50		if(o != len b)
51			b = b[0:o];
52		reqs <-= ref Rq.Result(b, rc);
53	}while(<-rc != -1);
54}
55
56Slipesc, Slipend: con (1<<8) + iota;
57Slipsize: con 1006;	# rfc's suggestion
58
59slipin(c: byte, esc: int): int
60{
61	if(esc == Slipesc){	# last byte was Esc
62		if(c == Eend)
63			c = End;
64		else if(c == Eesc)
65			c = Esc;
66	}else{
67		if(c == Esc)
68			return Slipesc;
69		if(c == End)
70			return Slipend;
71	}
72	return int c;
73}
74
75decode(reqs: chan of ref Rq)
76{
77	sys := load Sys Sys->PATH;
78	reqs <-= ref Rq.Start(sys->pctl(0, nil));
79	buf := array[8192] of byte;
80	b := array[Slipsize] of byte;
81	rc := chan of int;
82	c := 0;
83	o := 0;
84	for(;;){
85		reqs <-= ref Rq.Fill(buf, rc);
86		if((n := <-rc) <= 0){
87			if(n < 0)
88				exit;
89			break;
90		}
91		for(i := 0; i < n; i++){
92			c = slipin(buf[i], c);
93			if(c == Slipend){
94				if(o != 0){
95					reqs <-= ref Rq.Result(b[0:o], rc);
96					if(<-rc == -1)
97						exit;
98					b = array[Slipsize] of byte;
99					o = 0;
100				}
101			}else if(c != Slipesc){
102				if(o >= len b){
103					t := array[3*len b/2] of byte;
104					t[0:] = b;
105					b = t;
106				}
107				b[o++] = byte c;
108			}
109		}
110	}
111	# partial block discarded
112	reqs <-= ref Rq.Finished(nil);
113}
114