xref: /plan9/sys/src/cmd/diff/diffio.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1*3e12c5d1SDavid du Colombier #include <u.h>
2*3e12c5d1SDavid du Colombier #include <libc.h>
3*3e12c5d1SDavid du Colombier #include <bio.h>
4*3e12c5d1SDavid du Colombier #include "diff.h"
5*3e12c5d1SDavid du Colombier 
6*3e12c5d1SDavid du Colombier struct line {
7*3e12c5d1SDavid du Colombier 	int	serial;
8*3e12c5d1SDavid du Colombier 	int	value;
9*3e12c5d1SDavid du Colombier };
10*3e12c5d1SDavid du Colombier extern struct line *file[2];
11*3e12c5d1SDavid du Colombier extern int len[2];
12*3e12c5d1SDavid du Colombier extern long *ixold, *ixnew;
13*3e12c5d1SDavid du Colombier extern int *J;
14*3e12c5d1SDavid du Colombier 
15*3e12c5d1SDavid du Colombier static Biobuf *input[2];
16*3e12c5d1SDavid du Colombier static char *file1, *file2;
17*3e12c5d1SDavid du Colombier static int firstchange;
18*3e12c5d1SDavid du Colombier 
19*3e12c5d1SDavid du Colombier #define MAXLINELEN	4096
20*3e12c5d1SDavid du Colombier #define MIN(x, y)	((x) < (y) ? (x): (y))
21*3e12c5d1SDavid du Colombier 
22*3e12c5d1SDavid du Colombier static int
23*3e12c5d1SDavid du Colombier readline(Biobuf *bp, char *buf)
24*3e12c5d1SDavid du Colombier {
25*3e12c5d1SDavid du Colombier 	int c;
26*3e12c5d1SDavid du Colombier 	char *p, *e;
27*3e12c5d1SDavid du Colombier 
28*3e12c5d1SDavid du Colombier 	p = buf;
29*3e12c5d1SDavid du Colombier 	e = p + MAXLINELEN-1;
30*3e12c5d1SDavid du Colombier 	do {
31*3e12c5d1SDavid du Colombier 		c = Bgetc(bp);
32*3e12c5d1SDavid du Colombier 		if (c < 0) {
33*3e12c5d1SDavid du Colombier 			if (p == buf)
34*3e12c5d1SDavid du Colombier 				return -1;
35*3e12c5d1SDavid du Colombier 			break;
36*3e12c5d1SDavid du Colombier 		}
37*3e12c5d1SDavid du Colombier 		if (c == '\n')
38*3e12c5d1SDavid du Colombier 			break;
39*3e12c5d1SDavid du Colombier 		*p++ = c;
40*3e12c5d1SDavid du Colombier 	} while (p < e);
41*3e12c5d1SDavid du Colombier 	*p = 0;
42*3e12c5d1SDavid du Colombier 	if (c != '\n' && c >= 0) {
43*3e12c5d1SDavid du Colombier 		do c = Bgetc(bp);
44*3e12c5d1SDavid du Colombier 		while (c >= 0 && c != '\n');
45*3e12c5d1SDavid du Colombier 	}
46*3e12c5d1SDavid du Colombier 	return p - buf;
47*3e12c5d1SDavid du Colombier }
48*3e12c5d1SDavid du Colombier 
49*3e12c5d1SDavid du Colombier #define HALFLONG 16
50*3e12c5d1SDavid du Colombier #define low(x)	(x&((1L<<HALFLONG)-1))
51*3e12c5d1SDavid du Colombier #define high(x)	(x>>HALFLONG)
52*3e12c5d1SDavid du Colombier 
53*3e12c5d1SDavid du Colombier /*
54*3e12c5d1SDavid du Colombier  * hashing has the effect of
55*3e12c5d1SDavid du Colombier  * arranging line in 7-bit bytes and then
56*3e12c5d1SDavid du Colombier  * summing 1-s complement in 16-bit hunks
57*3e12c5d1SDavid du Colombier  */
58*3e12c5d1SDavid du Colombier static int
59*3e12c5d1SDavid du Colombier readhash(Biobuf *bp, char *buf)
60*3e12c5d1SDavid du Colombier {
61*3e12c5d1SDavid du Colombier 	long sum;
62*3e12c5d1SDavid du Colombier 	unsigned shift;
63*3e12c5d1SDavid du Colombier 	char *p;
64*3e12c5d1SDavid du Colombier 	int len, space;
65*3e12c5d1SDavid du Colombier 
66*3e12c5d1SDavid du Colombier 	sum = 1;
67*3e12c5d1SDavid du Colombier 	shift = 0;
68*3e12c5d1SDavid du Colombier 	if ((len = readline(bp, buf)) == -1)
69*3e12c5d1SDavid du Colombier 		return 0;
70*3e12c5d1SDavid du Colombier 	p = buf;
71*3e12c5d1SDavid du Colombier 	switch(bflag)	/* various types of white space handling */
72*3e12c5d1SDavid du Colombier 	{
73*3e12c5d1SDavid du Colombier 	case 0:
74*3e12c5d1SDavid du Colombier 		while (len--) {
75*3e12c5d1SDavid du Colombier 			sum += (long)*p++ << (shift &= (HALFLONG-1));
76*3e12c5d1SDavid du Colombier 			shift += 7;
77*3e12c5d1SDavid du Colombier 		}
78*3e12c5d1SDavid du Colombier 		break;
79*3e12c5d1SDavid du Colombier 	case 1:
80*3e12c5d1SDavid du Colombier 		/*
81*3e12c5d1SDavid du Colombier 		 * coalesce multiple white-space
82*3e12c5d1SDavid du Colombier 		 */
83*3e12c5d1SDavid du Colombier 		for (space = 0; len--; p++) {
84*3e12c5d1SDavid du Colombier 			if (isspace(*p)) {
85*3e12c5d1SDavid du Colombier 				space++;
86*3e12c5d1SDavid du Colombier 				continue;
87*3e12c5d1SDavid du Colombier 			}
88*3e12c5d1SDavid du Colombier 			if (space) {
89*3e12c5d1SDavid du Colombier 				shift += 7;
90*3e12c5d1SDavid du Colombier 				space = 0;
91*3e12c5d1SDavid du Colombier 			}
92*3e12c5d1SDavid du Colombier 			sum += (long)*p << (shift &= (HALFLONG-1));
93*3e12c5d1SDavid du Colombier 			shift += 7;
94*3e12c5d1SDavid du Colombier 		}
95*3e12c5d1SDavid du Colombier 		break;
96*3e12c5d1SDavid du Colombier 	default:
97*3e12c5d1SDavid du Colombier 		/*
98*3e12c5d1SDavid du Colombier 		 * strip all white-space
99*3e12c5d1SDavid du Colombier 		 */
100*3e12c5d1SDavid du Colombier 		while (len--) {
101*3e12c5d1SDavid du Colombier 			if (isspace(*p)) {
102*3e12c5d1SDavid du Colombier 				p++;
103*3e12c5d1SDavid du Colombier 				continue;
104*3e12c5d1SDavid du Colombier 			}
105*3e12c5d1SDavid du Colombier 			sum += (long)*p++ << (shift &= (HALFLONG-1));
106*3e12c5d1SDavid du Colombier 			shift += 7;
107*3e12c5d1SDavid du Colombier 		}
108*3e12c5d1SDavid du Colombier 		break;
109*3e12c5d1SDavid du Colombier 	}
110*3e12c5d1SDavid du Colombier 	sum = low(sum) + high(sum);
111*3e12c5d1SDavid du Colombier 	return ((short)low(sum) + (short)high(sum));
112*3e12c5d1SDavid du Colombier }
113*3e12c5d1SDavid du Colombier 
114*3e12c5d1SDavid du Colombier Biobuf *
115*3e12c5d1SDavid du Colombier prepare(int i, char *arg)
116*3e12c5d1SDavid du Colombier {
117*3e12c5d1SDavid du Colombier 	struct line *p;
118*3e12c5d1SDavid du Colombier 	int j, h;
119*3e12c5d1SDavid du Colombier 	Biobuf *bp;
120*3e12c5d1SDavid du Colombier 	char *cp, buf[MAXLINELEN];
121*3e12c5d1SDavid du Colombier 	int nbytes;
122*3e12c5d1SDavid du Colombier 	Rune r;
123*3e12c5d1SDavid du Colombier 
124*3e12c5d1SDavid du Colombier 	bp = Bopen(arg, OREAD);
125*3e12c5d1SDavid du Colombier 	if (!bp) {
126*3e12c5d1SDavid du Colombier 		panic(mflag ? 0: 2, "cannot open %s\n", arg);
127*3e12c5d1SDavid du Colombier 		return 0;
128*3e12c5d1SDavid du Colombier 	}
129*3e12c5d1SDavid du Colombier 	nbytes = Bread(bp, buf, MIN(1024, MAXLINELEN));
130*3e12c5d1SDavid du Colombier 	if (nbytes > 0) {
131*3e12c5d1SDavid du Colombier 		cp = buf;
132*3e12c5d1SDavid du Colombier 		while (cp < buf+nbytes-1) {
133*3e12c5d1SDavid du Colombier 			/*
134*3e12c5d1SDavid du Colombier 			 * heuristic for a binary file in the
135*3e12c5d1SDavid du Colombier 			 * brave new UNICODE world
136*3e12c5d1SDavid du Colombier 			 */
137*3e12c5d1SDavid du Colombier 			cp += chartorune(&r, cp);
138*3e12c5d1SDavid du Colombier 			if (r == 0 || (r > 0x7f && r <= 0xa0)) {
139*3e12c5d1SDavid du Colombier 				Bclose(bp);
140*3e12c5d1SDavid du Colombier 				panic(mflag ? 0: 2, "binary file %s\n", arg);
141*3e12c5d1SDavid du Colombier 				return 0;
142*3e12c5d1SDavid du Colombier 			}
143*3e12c5d1SDavid du Colombier 		}
144*3e12c5d1SDavid du Colombier 		Bseek(bp, 0, 0);
145*3e12c5d1SDavid du Colombier 	}
146*3e12c5d1SDavid du Colombier 	p = MALLOC(struct line, 3);
147*3e12c5d1SDavid du Colombier 	for (j = 0; h = readhash(bp, buf); p[j].value = h)
148*3e12c5d1SDavid du Colombier 		p = REALLOC(p, struct line, (++j+3));
149*3e12c5d1SDavid du Colombier 	len[i] = j;
150*3e12c5d1SDavid du Colombier 	file[i] = p;
151*3e12c5d1SDavid du Colombier 	input[i] = bp;			/*fix*/
152*3e12c5d1SDavid du Colombier 	if (i == 0) {			/*fix*/
153*3e12c5d1SDavid du Colombier 		file1 = arg;
154*3e12c5d1SDavid du Colombier 		firstchange = 0;
155*3e12c5d1SDavid du Colombier 	}
156*3e12c5d1SDavid du Colombier 	else
157*3e12c5d1SDavid du Colombier 		file2 = arg;
158*3e12c5d1SDavid du Colombier 	return bp;
159*3e12c5d1SDavid du Colombier }
160*3e12c5d1SDavid du Colombier 
161*3e12c5d1SDavid du Colombier static int
162*3e12c5d1SDavid du Colombier squishspace(char *buf)
163*3e12c5d1SDavid du Colombier {
164*3e12c5d1SDavid du Colombier 	char *p, *q;
165*3e12c5d1SDavid du Colombier 	int space;
166*3e12c5d1SDavid du Colombier 
167*3e12c5d1SDavid du Colombier 	for (space = 0, q = p = buf; *q; q++) {
168*3e12c5d1SDavid du Colombier 		if (isspace(*q)) {
169*3e12c5d1SDavid du Colombier 			space++;
170*3e12c5d1SDavid du Colombier 			continue;
171*3e12c5d1SDavid du Colombier 		}
172*3e12c5d1SDavid du Colombier 		if (space && bflag == 1) {
173*3e12c5d1SDavid du Colombier 			*p++ = ' ';
174*3e12c5d1SDavid du Colombier 			space = 0;
175*3e12c5d1SDavid du Colombier 		}
176*3e12c5d1SDavid du Colombier 		*p++ = *q;
177*3e12c5d1SDavid du Colombier 	}
178*3e12c5d1SDavid du Colombier 	*p = 0;
179*3e12c5d1SDavid du Colombier 	return p - buf;
180*3e12c5d1SDavid du Colombier }
181*3e12c5d1SDavid du Colombier 
182*3e12c5d1SDavid du Colombier /*
183*3e12c5d1SDavid du Colombier  * need to fix up for unexpected EOF's
184*3e12c5d1SDavid du Colombier  */
185*3e12c5d1SDavid du Colombier void
186*3e12c5d1SDavid du Colombier check(Biobuf *bf, Biobuf *bt)
187*3e12c5d1SDavid du Colombier {
188*3e12c5d1SDavid du Colombier 	int f, t, flen, tlen;
189*3e12c5d1SDavid du Colombier 	char fbuf[MAXLINELEN], tbuf[MAXLINELEN];
190*3e12c5d1SDavid du Colombier 
191*3e12c5d1SDavid du Colombier 	ixold[0] = ixnew[0] = 0;
192*3e12c5d1SDavid du Colombier 	for (f = t = 1; f < len[0]; f++) {
193*3e12c5d1SDavid du Colombier 		flen = readline(bf, fbuf);
194*3e12c5d1SDavid du Colombier 		ixold[f] = ixold[f-1] + flen + 1;		/* ftell(bf) */
195*3e12c5d1SDavid du Colombier 		if (J[f] == 0)
196*3e12c5d1SDavid du Colombier 			continue;
197*3e12c5d1SDavid du Colombier 		do {
198*3e12c5d1SDavid du Colombier 			tlen = readline(bt, tbuf);
199*3e12c5d1SDavid du Colombier 			ixnew[t] = ixnew[t-1] + tlen + 1;	/* ftell(bt) */
200*3e12c5d1SDavid du Colombier 		} while (t++ < J[f]);
201*3e12c5d1SDavid du Colombier 		if (bflag) {
202*3e12c5d1SDavid du Colombier 			flen = squishspace(fbuf);
203*3e12c5d1SDavid du Colombier 			tlen = squishspace(tbuf);
204*3e12c5d1SDavid du Colombier 		}
205*3e12c5d1SDavid du Colombier 		if (flen != tlen || strcmp(fbuf, tbuf))
206*3e12c5d1SDavid du Colombier 			J[f] = 0;
207*3e12c5d1SDavid du Colombier 	}
208*3e12c5d1SDavid du Colombier 	while (t < len[1]) {
209*3e12c5d1SDavid du Colombier 		tlen = readline(bt, tbuf);
210*3e12c5d1SDavid du Colombier 		ixnew[t] = ixnew[t-1] + tlen + 1;	/* fseek(bt) */
211*3e12c5d1SDavid du Colombier 		t++;
212*3e12c5d1SDavid du Colombier 	}
213*3e12c5d1SDavid du Colombier }
214*3e12c5d1SDavid du Colombier 
215*3e12c5d1SDavid du Colombier static void
216*3e12c5d1SDavid du Colombier range(int a, int b, char *separator)
217*3e12c5d1SDavid du Colombier {
218*3e12c5d1SDavid du Colombier 	Bprint(&stdout, "%d", a > b ? b: a);
219*3e12c5d1SDavid du Colombier 	if (a < b)
220*3e12c5d1SDavid du Colombier 		Bprint(&stdout, "%s%d", separator, b);
221*3e12c5d1SDavid du Colombier }
222*3e12c5d1SDavid du Colombier 
223*3e12c5d1SDavid du Colombier static void
224*3e12c5d1SDavid du Colombier fetch(long *f, int a, int b, Biobuf *bp, char *s)
225*3e12c5d1SDavid du Colombier {
226*3e12c5d1SDavid du Colombier 	char buf[MAXLINELEN];
227*3e12c5d1SDavid du Colombier 
228*3e12c5d1SDavid du Colombier 	Bseek(bp, f[a-1], 0);
229*3e12c5d1SDavid du Colombier 	while (a++ <= b) {
230*3e12c5d1SDavid du Colombier 		readline(bp, buf);
231*3e12c5d1SDavid du Colombier 		Bprint(&stdout, "%s%s\n", s, buf);
232*3e12c5d1SDavid du Colombier 	}
233*3e12c5d1SDavid du Colombier }
234*3e12c5d1SDavid du Colombier 
235*3e12c5d1SDavid du Colombier void
236*3e12c5d1SDavid du Colombier change(int a, int b, int c, int d)
237*3e12c5d1SDavid du Colombier {
238*3e12c5d1SDavid du Colombier 	if (a > b && c > d)
239*3e12c5d1SDavid du Colombier 		return;
240*3e12c5d1SDavid du Colombier 	anychange = 1;
241*3e12c5d1SDavid du Colombier 	if (mflag && firstchange == 0) {
242*3e12c5d1SDavid du Colombier 		Bprint(&stdout, "diff %s %s\n", file1, file2);
243*3e12c5d1SDavid du Colombier 		firstchange = 1;
244*3e12c5d1SDavid du Colombier 	}
245*3e12c5d1SDavid du Colombier 	if (mode != 'f') {
246*3e12c5d1SDavid du Colombier 		range(a, b, ",");
247*3e12c5d1SDavid du Colombier 		Bputc(&stdout, a > b ? 'a': c > d ? 'd': 'c');
248*3e12c5d1SDavid du Colombier 		if (mode != 'e')
249*3e12c5d1SDavid du Colombier 			range(c, d, ",");
250*3e12c5d1SDavid du Colombier 	}
251*3e12c5d1SDavid du Colombier 	else {
252*3e12c5d1SDavid du Colombier 		Bputc(&stdout, a > b ? 'a': c > d ? 'd': 'c');
253*3e12c5d1SDavid du Colombier 		range(a, b, " ");
254*3e12c5d1SDavid du Colombier 	}
255*3e12c5d1SDavid du Colombier 	Bputc(&stdout, '\n');
256*3e12c5d1SDavid du Colombier 	if (mode == 0) {
257*3e12c5d1SDavid du Colombier 		fetch(ixold, a, b, input[0], "< ");
258*3e12c5d1SDavid du Colombier 		if (a <= b && c <= d)
259*3e12c5d1SDavid du Colombier 			Bprint(&stdout, "---\n");
260*3e12c5d1SDavid du Colombier 	}
261*3e12c5d1SDavid du Colombier 	fetch(ixnew, c, d, input[1], mode == 0 ? "> ": "");
262*3e12c5d1SDavid du Colombier 	if (mode != 0 && c <= d)
263*3e12c5d1SDavid du Colombier 		Bprint(&stdout, ".\n");
264*3e12c5d1SDavid du Colombier }
265