xref: /inferno-os/appl/cmd/bytes.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement Bytes;
2include "sys.m";
3	sys: Sys;
4	stderr: ref Sys->FD;
5include "draw.m";
6include "bufio.m";
7	bufio: Bufio;
8	Iobuf: import bufio;
9
10stdin, stdout: ref Iobuf;
11
12Bytes: module {
13	init: fn(nil: ref Draw->Context, argv: list of string);
14};
15
16usage()
17{
18	sys->fprint(stderr, "usage: bytes start end [bytes]\n");
19	raise "fail:usage";
20}
21
22END: con 16r7fffffff;
23init(nil: ref Draw->Context, argv: list of string)
24{
25	sys = load Sys Sys->PATH;
26	stderr = sys->fildes(2);
27	bufio = load Bufio Bufio->PATH;
28	if (bufio == nil) {
29		sys->fprint(stderr, "bytes: cannot load %s: %r\n", Bufio->PATH);
30		raise "fail:bad module";
31	}
32	stdin = bufio->fopen(sys->fildes(0), Sys->OREAD);
33	stdout = bufio->fopen(sys->fildes(1), Sys->OWRITE);
34	start := end := END;
35	if (len argv < 3)
36		usage();
37	argv = tl argv;
38	if (hd argv != "end")
39		start = int hd argv;
40	argv = tl argv;
41	if (hd argv != "end")
42		end = int hd argv;
43	if (end < start) {
44		sys->fprint(stderr, "bytes: out of order range\n");
45		raise "fail:bad range";
46	}
47	argv = tl argv;
48	if (argv == nil)
49		showbytes(start, end);
50	else {
51		if (tl argv != nil)
52			usage();
53		b := s2bytes(hd argv);
54		setbytes(start, end, b);
55	}
56	stdout.close();
57}
58
59showbytes(start, end: int)
60{
61	buf := array[Sys->ATOMICIO] of byte;
62	hold := array[Sys->UTFmax] of byte;
63	tot := 0;
64	nhold := 0;
65	while (tot < end && (n := stdin.read(buf[nhold:], len buf - nhold)) > 0) {
66		sys->fprint(stderr, "bytes: read %d bytes\n", n);
67		if (tot + n < start)
68			continue;
69		sb := 0;
70		eb := n;
71		if (start > tot)
72			sb = start - tot;
73		if (tot + n > end)
74			eb = end - tot;
75		nhold = putbytes(buf[sb:eb], hold);
76		buf[0:] = hold[0:nhold];
77		tot += n - nhold;
78	}
79	sys->fprint(stderr, "out of loop\n");
80	flushbytes(hold[0:nhold]);
81}
82
83setbytes(start, end: int, d: array of byte)
84{
85	buf := array[Sys->ATOMICIO] of byte;
86	tot := 0;
87	while ((n := stdin.read(buf, len buf)) > 0) {
88		if (tot + n < start || tot >= end) {
89			stdout.write(buf, n);
90			continue;
91		}
92		if (tot <= start) {
93			stdout.write(buf[0:start-tot], start-tot);
94			stdout.write(d, len d);
95			if (end == END)
96				return;
97		}
98		if (tot + n >= end)
99			stdout.write(buf[end - tot:], n - (end - tot));
100		tot += n;
101	}
102	if (tot == start || start == END)
103		stdout.write(d, len d);
104}
105
106putbytes(d: array of byte, hold: array of byte): int
107{
108	i := 0;
109	while (i < len d) {
110		(c, n, ok) := sys->byte2char(d, i);
111		if (ok && n > 0) {
112			if (c == '\\')
113				stdout.putc('\\');
114			stdout.putc(c);
115		} else {
116			if (n == 0) {
117				hold[0:] = d[i:];
118				return len d - i;
119			} else {
120				putbyte(d[i]);
121				n = 1;
122			}
123		}
124		i += n;
125	}
126	return 0;
127}
128
129flushbytes(hold: array of byte)
130{
131	for (i := 0; i < len hold; i++)
132		putbyte(hold[i]);
133}
134
135putbyte(b: byte)
136{
137	stdout.puts(sys->sprint("\\%2.2X", int b));
138}
139
140isbschar(c: int): int
141{
142	case c {
143	'n' or 'r' or 't' or 'v' =>
144		return 1;
145	}
146	return 0;
147}
148
149s2bytes(s: string): array of byte
150{
151	d := array[len s + 2] of byte;
152	j := 0;
153	for (i := 0; i < len s; i++) {
154		if (s[i] == '\\') {
155			if (i >= len s - 1 || (!isbschar(s[i+1]) && i >= len s - 2)) {
156				sys->fprint(stderr, "bytes: invalid backslash sequence\n");
157				raise "fail:bad args";
158			}
159			d = assure(d, j + 1);
160			if (isbschar(s[i+1])) {
161				case s[i+1] {
162				'n' =>	d[j++] = byte '\n';
163				'r' =>		d[j++] = byte '\r';
164				't' =>		d[j++] = byte '\t';
165				'v' =>	d[j++] = byte '\v';
166				'\\' =>	d[j++] = byte '\\';
167				* =>
168					sys->fprint(stderr, "bytes: invalid backslash sequence\n");
169					raise "fail:bad args";
170				}
171				i++;
172			} else if (!ishex(s[i+1]) || !ishex(s[i+2])) {
173				sys->fprint(stderr, "bytes: invalid backslash sequence\n");
174				raise "fail:bad args";
175			} else {
176				d[j++] = byte ((hex(s[i+1]) << 4) + hex(s[i+2]));
177				i += 2;
178			}
179		} else {
180			d = assure(d, j + 3);
181			j += sys->char2byte(s[i], d, j);
182		}
183	}
184	return d[0:j];
185}
186
187assure(d: array of byte, n: int): array of byte
188{
189	if (len d >= n)
190		return d;
191	nd := array[n] of byte;
192	nd[0:] = d;
193	return nd;
194}
195
196ishex(c: int): int
197{
198	return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
199}
200
201hex(c: int): int
202{
203	case c {
204	'0' to '9' =>
205		return c - '0';
206	'a' to 'f' =>
207		return c - 'a' + 10;
208	'A' to 'F' =>
209		return c-  'A' + 10;
210	}
211	return 0;
212}
213