forsyth20121205-174063a80cc13 years agoHistory
316 lines · 5.4 KB · Brainfuck
RawDownload
implement Xd; ## based on Plan9 xd# include "sys.m";include "draw.m";include "bufio.m"; Xd: module  {	init: fn(ctxt: ref Draw->Context, argv: list of string);}; sys : Sys;bufio : Bufio;Iobuf : import bufio;stdin, stdout, stderr : ref Sys->FD; wbytes := array [] of {	1,	2,	4,	8,};fmtchars : con "odx";fmtbases := array [] of {	8,	10,	16,};fwidths := array [] of {	3,	# 1o	3,	# 1d	2,	# 1x	6,	# 2o	5,	# 2d	4,	# 2x	11,	# 4o	10,	# 4d	8,	# 4x	22,	# 8o	20,	# 8d	16,	# 8x}; bytepos := array [16] of { * => 0 }; formats := array [10] of (int, int, int);	# (nbytes, base, fieldwidth)nformats := 0;addrbase := 16;repeats := 0;swab := 0;flush := 0;addr := big 0;output : ref Iobuf;pad : string;  init(nil : ref Draw->Context, argv : list of string){	sys = load Sys Sys->PATH;	stdin  = sys->fildes(0);	stdout = sys->fildes(1);	stderr = sys->fildes(2); 	bufio = load Bufio Bufio->PATH;	if (bufio == nil) {		sys->fprint(stderr, "cannot load bufio: %r\n");		raise "fail:init";	}	output = bufio->fopen(stdout, Sys->OWRITE);	if (argv == nil)		raise "fail:bad argv"; 	pad = string array [32] of { * => byte ' ' }; 	for (argv = tl argv; argv != nil; argv = tl argv) {		arg := hd argv;		if (arg == nil)			continue;		if (arg[0] != '-')			break; 		if (len arg == 2) {			case arg[1] {			'c' =>				addformat(0, 256);			'r' =>				repeats = 1;			's' =>				swab = 1;			'u' =>				flush = 1;			* =>				usage();			}			continue;		}		# XXX should allow -x1, -x		if (len arg == 3) {			n := 0;			baseix := strchr(fmtchars,arg[2]);			if (baseix == -1)				usage();			case arg[1] {			'a' =>				addrbase = fmtbases[baseix];				continue;			'b' or '1' =>	n = 0;			'w' or '2' =>	n = 1;			'l' or '4' =>	n = 2;			'v' or '8' =>	n = 3;			* =>				usage();			}			addformat(n, baseix);			continue;		}		usage();	}	if (nformats == 0)		addformat(2, 2);	# "4x" 	if (argv == nil)		dump(nil, 0);	else if (tl argv == nil)		dump(hd argv, 0);	else {		for (; argv != nil; argv = tl argv) {			dump(hd argv, 1);		}	}} usage(){	sys->fprint(stderr, "usage: xd [-u] [-r] [-s] [-a{odx}] [-c|{b1w2l4v8}{odx}] ... file ...\n");	raise "fail:usage";} strchr(s : string, ch : int) : int{	for (ix := 0; ix < len s; ix++)		if (s[ix] == ch)			return ix;	return -1;} addformat(widix, baseix : int){	nbytes := wbytes[widix];	if (nformats >= len formats) {		sys->fprint(stderr, "xd: too many formats\n");		raise "fail:error";	}	fw : int;	if (baseix == 256) {		# special -c case		formats[nformats++] = (nbytes, 256, 2);		fw = 2;	} else {		fw = fwidths[baseix + (widix *len fmtbases)];		formats[nformats++] = (nbytes, fmtbases[baseix], fw);	}	bpos := 0;	for (ix := 0; ix < 16; ix += nbytes) {		if (bytepos[ix] >= bpos)			bpos = bytepos[ix];		else {			d := bpos - bytepos[ix];			for (dix := ix; dix < 16; dix++)				bytepos[dix] += d;		}		bpos += fw + 1;	}} dump(path : string, title : int){	input := bufio->fopen(stdin, Sys->OREAD);	zeros := array [16] of {* => byte 0}; 	if (path != nil) {		input = bufio->open(path, Sys->OREAD);		if (input == nil) {			sys->fprint(stderr, "xd: cannot open %s: %r\n", path);			raise "fail:cannot open";		}	} 	if (title) {		output.puts(path);		output.putc('\n');	} 	addr = big 0;	star := 0;	obuf: array of byte; 	for (;;) {		n := 0;		buf := array [16] of byte;		while (n < 16 && (r := input.read(buf[n:], 16 - n)) > 0)			n += r;		if (n < 16)			buf[n:] = zeros[n:];		if (swab)			doswab(buf);		if (n == 16 && repeats) {			if (obuf != nil && buf[0]==obuf[0]) {				for (i := 0; i < 16; i++)					if (obuf[i] != buf[i])						break;				if (i == 16) {					addr += big 16;					if (star == 0) {						star++;						output.puts("*\n");					}					continue;				}			}			obuf = buf;			star = 0;		}		for (fmt := 0; fmt < nformats; fmt++) {			if (fmt == 0)				output.puts(big2str(addr, 7, addrbase, '0'));			else				output.puts(big2str(addr, 7, addrbase, ' '));			output.putc(' ');			(w, b, fw) := formats[fmt];			pdata(fw, w, b, n, buf);			output.putc('\n');			if (flush)				output.flush();		}		addr += big n;		if (n < 16) {			output.puts(big2str(addr, 7, addrbase, '0'));			output.putc('\n');			if (flush)				output.flush();			break;		}	}	output.flush();} hexchars : con "0123456789abcdef"; big2str(b : big, minw, base, padc  : int) : string{	s := "";	do {		d := int (b % big base);		s[len s] = hexchars[d];		b /= big base;	} while (b > big 0);	t := "";	if (len s < minw)		t = string array [minw] of { * => byte padc };	else		t = s;	for (i := len s - 1; i >= 0; i--)		t[len t - 1 - i] = s[i];	return t;} pdata(fw, n, base, dlen : int, data : array of byte){	nout := 0;	text := ""; 	for (i := 0; i < dlen; i += n) {		if (i != 0) {			padlen := bytepos[i] - nout;			output.puts(pad[0:padlen]);			nout += padlen;		}		if (base == 256) {			# special -c case			ch := int data[i];			case ch {			'\t' =>	text = "\\t";			'\r' =>	text = "\\r";			'\n' =>	text = "\\n";			'\b' =>	text = "\\b";			* =>				if (ch >= 16r7f || ' ' > ch)					text = sys->sprint("%.2x", ch);				else					text = sys->sprint("%c", ch);			}		} else {			v := big data[i];			for (ix := 1; ix < n; ix++)				v = (v << 8) + big data[i+ix];			text = big2str(v, fw, base, '0');		}		output.puts(text);		nout += len text;	}} doswab(b : array of byte){	ix := 0;	for (i := 0; i < 4; i++) {		(b[ix], b[ix+3]) = (b[ix+3], b[ix]);		(b[ix+1], b[ix+2]) = (b[ix+2], b[ix+1]);		ix += 4;	}}