xref: /inferno-os/appl/cmd/cmp.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement Cmp;
2
3include "sys.m";
4	sys: Sys;
5
6include "draw.m";
7	draw: Draw;
8
9include "arg.m";
10
11BUF: con 65536;
12stderr: ref Sys->FD;
13
14Cmp: module
15{
16	init: fn(nil: ref Draw->Context, argv: list of string);
17};
18
19init(nil: ref Draw->Context, args: list of string)
20{
21	sys = load Sys Sys->PATH;
22
23	lflag := Lflag := sflag := 0;
24	buf1 := array[BUF] of byte;
25	buf2 := array[BUF] of byte;
26
27	stderr = sys->fildes(2);
28
29	arg := load Arg Arg->PATH;
30	if(arg == nil){
31		sys->fprint(stderr, "cmp: cannot load %s: %r\n", Arg->PATH);
32		raise "fail:load";
33	}
34	arg->init(args);
35	while((op := arg->opt()) != 0)
36		case op {
37		'l' =>		lflag = 1;
38		'L' =>	Lflag = 1;
39		's' =>		sflag = 1;
40		* =>		usage();
41		}
42	args = arg->argv();
43	arg = nil;
44	if(args == nil)
45		usage();
46
47	if(len args < 2)
48		usage();
49	name1 := hd args;
50	args = tl args;
51
52	if((f1 := sys->open(name1, Sys->OREAD)) == nil){
53		sys->fprint(stderr, "cmp: can't open %s: %r\n",name1);
54		raise "fail:open";
55	}
56	name2 := hd args;
57	args = tl args;
58
59	if((f2 := sys->open(name2, Sys->OREAD)) == nil){
60		sys->fprint(stderr, "cmp: can't open %s: %r\n",name2);
61		raise "fail:open";
62	}
63
64	if(args != nil){
65		o := big hd args;
66		if(sys->seek(f1, o, 0) < big 0){
67			sys->fprint(stderr, "cmp: seek by offset1 failed: %r\n");
68			raise "fail:seek 1";
69		}
70		args = tl args;
71	}
72
73	if(args != nil){
74		o := big hd args;
75		if(sys->seek(f2, o, 0) < big 0){
76			sys->fprint(stderr, "cmp: seek by offset2 failed: %r");
77			raise "fail:seek 2";
78		}
79		args = tl args;
80	}
81	if(args != nil)
82		usage();
83	nc := big 1;
84	l := big 1;
85	diff := 0;
86	b1, b2: array of byte;
87	for(;;){
88		if(len b1 == 0){
89			nr := sys->read(f1, buf1, BUF);
90			if(nr < 0){
91				if(!sflag)
92					sys->print("error on %s after %bd bytes\n", name1, nc-big 1);
93				raise "fail:read error";
94			}
95			b1 = buf1[0: nr];
96		}
97		if(len b2 == 0){
98			nr := sys->read(f2, buf2, BUF);
99			if(nr < 0){
100				if(!sflag)
101					sys->print("error on %s after %bd bytes\n", name2, nc-big 1);
102				raise "fail:read error";
103			}
104			b2 = buf2[0: nr];
105		}
106		n := len b2;
107		if(n > len b1)
108			n = len b1;
109		if(n == 0)
110			break;
111		for(i:=0; i<n; i++){
112			if(Lflag && b1[i]== byte '\n')
113				l++;
114			if(b1[i] != b2[i]){
115				if(!lflag){
116					if(!sflag){
117						sys->print("%s %s differ: char %bd", name1, name2, nc+big i);
118						if(Lflag)
119							sys->print(" line %bd\n", l);
120						else
121							sys->print("\n");
122					}
123					raise "fail:differ";
124				}
125				sys->print("%6bd 0x%.2x 0x%.2x\n", nc+big i, int b1[i], int b2[i]);
126				diff = 1;
127			}
128		}
129		nc += big n;
130		b1 = b1[n:];
131		b2 = b2[n:];
132	}
133	if(len b1 != len b2) {
134		nc--;
135		if(len b1 > len b2)
136			sys->print("EOF on %s after %bd bytes\n", name2, nc);
137		else
138			sys->print("EOF on %s after %bd bytes\n", name1, nc);
139		raise "fail:EOF";
140	}
141	if(diff)
142		raise "fail:differ";
143	exit;
144}
145
146
147usage()
148{
149	sys->fprint(stderr, "Usage: cmp [-lsL] file1 file2 [offset1 [offset2] ]\n");
150	raise "fail:usage";
151}
152