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