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