shithub: purgatorio

ref: 0644aa11c120a581eec1d47c66208e08b946ec08
dir: /appl/cmd/cmp.b/

View raw version
implement Cmp;

include "sys.m";
	sys: Sys;

include "draw.m";
	draw: Draw;

include "arg.m";

BUF: con 65536;
stderr: ref Sys->FD;

Cmp: module
{
	init: fn(nil: ref Draw->Context, argv: list of string);
};

init(nil: ref Draw->Context, args: list of string)
{
	sys = load Sys Sys->PATH;

	lflag := Lflag := sflag := 0;
	buf1 := array[BUF] of byte;
	buf2 := array[BUF] of byte;

	stderr = sys->fildes(2);

	arg := load Arg Arg->PATH;	
	if(arg == nil){
		sys->fprint(stderr, "cmp: cannot load %s: %r\n", Arg->PATH);
		raise "fail:load";
	}
	arg->init(args);
	while((op := arg->opt()) != 0)
		case op {
		'l' =>		lflag = 1;
		'L' =>	Lflag = 1;
		's' =>		sflag = 1;
		* =>		usage();
		}
	args = arg->argv();
	arg = nil;
	if(args == nil)
		usage();

	if(len args < 2)
		usage();
	name1 := hd args;
	args = tl args;

	if((f1 := sys->open(name1, Sys->OREAD)) == nil){
		sys->fprint(stderr, "cmp: can't open %s: %r\n",name1);
		raise "fail:open";
	}
	name2 := hd args;
	args = tl args;

	if((f2 := sys->open(name2, Sys->OREAD)) == nil){
		sys->fprint(stderr, "cmp: can't open %s: %r\n",name2);
		raise "fail:open";
	}

	if(args != nil){
		o := big hd args;
		if(sys->seek(f1, o, 0) < big 0){
			sys->fprint(stderr, "cmp: seek by offset1 failed: %r\n");
			raise "fail:seek 1";
		}
		args = tl args;
	}

	if(args != nil){
		o := big hd args;
		if(sys->seek(f2, o, 0) < big 0){
			sys->fprint(stderr, "cmp: seek by offset2 failed: %r");
			raise "fail:seek 2";
		}
		args = tl args;
	}
	if(args != nil)
		usage();
	nc := big 1;
	l := big 1;
	diff := 0;
	b1, b2: array of byte;
	for(;;){
		if(len b1 == 0){
			nr := sys->read(f1, buf1, BUF);
			if(nr < 0){
				if(!sflag)
					sys->print("error on %s after %bd bytes\n", name1, nc-big 1);
				raise "fail:read error";
			}
			b1 = buf1[0: nr];
		}
		if(len b2 == 0){
			nr := sys->read(f2, buf2, BUF);
			if(nr < 0){
				if(!sflag)
					sys->print("error on %s after %bd bytes\n", name2, nc-big 1);
				raise "fail:read error";
			}
			b2 = buf2[0: nr];
		}
		n := len b2;
		if(n > len b1)
			n = len b1;
		if(n == 0)
			break;
		for(i:=0; i<n; i++){
			if(Lflag && b1[i]== byte '\n')
				l++;
			if(b1[i] != b2[i]){
				if(!lflag){
					if(!sflag){
						sys->print("%s %s differ: char %bd", name1, name2, nc+big i);
						if(Lflag)
							sys->print(" line %bd\n", l);
						else
							sys->print("\n");
					}
					raise "fail:differ";
				}
				sys->print("%6bd 0x%.2x 0x%.2x\n", nc+big i, int b1[i], int b2[i]);
				diff = 1;
			}
		}
		nc += big n;
		b1 = b1[n:];
		b2 = b2[n:];
	}
	if(len b1 != len b2) {
		nc--;
		if(len b1 > len b2)
			sys->print("EOF on %s after %bd bytes\n", name2, nc);
		else 
			sys->print("EOF on %s after %bd bytes\n", name1, nc);
		raise "fail:EOF";
	}
	if(diff)
		raise "fail:differ";
	exit;
}


usage() 
{
	sys->fprint(stderr, "Usage: cmp [-lsL] file1 file2 [offset1 [offset2] ]\n");
	raise "fail:usage";
}