ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/cmd/bytes.b/
implement Bytes;
include "sys.m";
sys: Sys;
stderr: ref Sys->FD;
include "draw.m";
include "bufio.m";
bufio: Bufio;
Iobuf: import bufio;
stdin, stdout: ref Iobuf;
Bytes: module {
init: fn(nil: ref Draw->Context, argv: list of string);
};
usage()
{
sys->fprint(stderr, "usage: bytes start end [bytes]\n");
raise "fail:usage";
}
END: con 16r7fffffff;
init(nil: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
stderr = sys->fildes(2);
bufio = load Bufio Bufio->PATH;
if (bufio == nil) {
sys->fprint(stderr, "bytes: cannot load %s: %r\n", Bufio->PATH);
raise "fail:bad module";
}
stdin = bufio->fopen(sys->fildes(0), Sys->OREAD);
stdout = bufio->fopen(sys->fildes(1), Sys->OWRITE);
start := end := END;
if (len argv < 3)
usage();
argv = tl argv;
if (hd argv != "end")
start = int hd argv;
argv = tl argv;
if (hd argv != "end")
end = int hd argv;
if (end < start) {
sys->fprint(stderr, "bytes: out of order range\n");
raise "fail:bad range";
}
argv = tl argv;
if (argv == nil)
showbytes(start, end);
else {
if (tl argv != nil)
usage();
b := s2bytes(hd argv);
setbytes(start, end, b);
}
stdout.close();
}
showbytes(start, end: int)
{
buf := array[Sys->ATOMICIO] of byte;
hold := array[Sys->UTFmax] of byte;
tot := 0;
nhold := 0;
while (tot < end && (n := stdin.read(buf[nhold:], len buf - nhold)) > 0) {
sys->fprint(stderr, "bytes: read %d bytes\n", n);
if (tot + n < start)
continue;
sb := 0;
eb := n;
if (start > tot)
sb = start - tot;
if (tot + n > end)
eb = end - tot;
nhold = putbytes(buf[sb:eb], hold);
buf[0:] = hold[0:nhold];
tot += n - nhold;
}
sys->fprint(stderr, "out of loop\n");
flushbytes(hold[0:nhold]);
}
setbytes(start, end: int, d: array of byte)
{
buf := array[Sys->ATOMICIO] of byte;
tot := 0;
while ((n := stdin.read(buf, len buf)) > 0) {
if (tot + n < start || tot >= end) {
stdout.write(buf, n);
continue;
}
if (tot <= start) {
stdout.write(buf[0:start-tot], start-tot);
stdout.write(d, len d);
if (end == END)
return;
}
if (tot + n >= end)
stdout.write(buf[end - tot:], n - (end - tot));
tot += n;
}
if (tot == start || start == END)
stdout.write(d, len d);
}
putbytes(d: array of byte, hold: array of byte): int
{
i := 0;
while (i < len d) {
(c, n, ok) := sys->byte2char(d, i);
if (ok && n > 0) {
if (c == '\\')
stdout.putc('\\');
stdout.putc(c);
} else {
if (n == 0) {
hold[0:] = d[i:];
return len d - i;
} else {
putbyte(d[i]);
n = 1;
}
}
i += n;
}
return 0;
}
flushbytes(hold: array of byte)
{
for (i := 0; i < len hold; i++)
putbyte(hold[i]);
}
putbyte(b: byte)
{
stdout.puts(sys->sprint("\\%2.2X", int b));
}
isbschar(c: int): int
{
case c {
'n' or 'r' or 't' or 'v' =>
return 1;
}
return 0;
}
s2bytes(s: string): array of byte
{
d := array[len s + 2] of byte;
j := 0;
for (i := 0; i < len s; i++) {
if (s[i] == '\\') {
if (i >= len s - 1 || (!isbschar(s[i+1]) && i >= len s - 2)) {
sys->fprint(stderr, "bytes: invalid backslash sequence\n");
raise "fail:bad args";
}
d = assure(d, j + 1);
if (isbschar(s[i+1])) {
case s[i+1] {
'n' => d[j++] = byte '\n';
'r' => d[j++] = byte '\r';
't' => d[j++] = byte '\t';
'v' => d[j++] = byte '\v';
'\\' => d[j++] = byte '\\';
* =>
sys->fprint(stderr, "bytes: invalid backslash sequence\n");
raise "fail:bad args";
}
i++;
} else if (!ishex(s[i+1]) || !ishex(s[i+2])) {
sys->fprint(stderr, "bytes: invalid backslash sequence\n");
raise "fail:bad args";
} else {
d[j++] = byte ((hex(s[i+1]) << 4) + hex(s[i+2]));
i += 2;
}
} else {
d = assure(d, j + 3);
j += sys->char2byte(s[i], d, j);
}
}
return d[0:j];
}
assure(d: array of byte, n: int): array of byte
{
if (len d >= n)
return d;
nd := array[n] of byte;
nd[0:] = d;
return nd;
}
ishex(c: int): int
{
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
hex(c: int): int
{
case c {
'0' to '9' =>
return c - '0';
'a' to 'f' =>
return c - 'a' + 10;
'A' to 'F' =>
return c- 'A' + 10;
}
return 0;
}