ref: db1eb844461b07a25ca49117851fa874fd88e065
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; }