xref: /illumos-gate/usr/src/cmd/diff/diffh.c (revision d48be21240dfd051b689384ce2b23479d757f2d8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <ctype.h>
35 #include <locale.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <limits.h>
39 #include <stdarg.h>
40 
41 #define	C		3
42 #define	RANGE		30
43 #define	LEN		255
44 #define	INF		16384
45 
46 char *text[2][RANGE];
47 long lineno[2] = {1, 1};	/* no. of 1st stored line in each file */
48 int ntext[2];		/* number of stored lines in each */
49 long n0, n1;		/* scan pointer in each */
50 int bflag;
51 int debug = 0;
52 FILE *file[2];
53 static int diffFound = 0;
54 
55 static char *getl(int f, long n);
56 static void clrl(int f, long n);
57 static void movstr(char *s, char *t);
58 static int easysynch(void);
59 static int output(int a, int b);
60 static void change(long a, int b, long c, int d, char *s);
61 static void range(long a, int b);
62 static int cmp(char *s, char *t);
63 static FILE *dopen(char *f1, char *f2);
64 static void progerr(char *s);
65 static void error(char *err, ...);
66 static int hardsynch(void);
67 
68 	/* return pointer to line n of file f */
69 static char *
70 getl(int f, long n)
71 {
72 	char *t;
73 	int delta, nt;
74 
75 again:
76 	delta = n - lineno[f];
77 	nt = ntext[f];
78 	if (delta < 0)
79 		progerr("1");
80 	if (delta < nt)
81 		return (text[f][delta]);
82 	if (delta > nt)
83 		progerr("2");
84 	if (nt >= RANGE)
85 		progerr("3");
86 	if (feof(file[f]))
87 		return (NULL);
88 	t = text[f][nt];
89 	if (t == 0) {
90 		t = text[f][nt] = (char *)malloc(LEN+1);
91 		if (t == NULL)
92 			if (hardsynch())
93 				goto again;
94 			else
95 				progerr("5");
96 	}
97 	t = fgets(t, LEN, file[f]);
98 	if (t != NULL)
99 		ntext[f]++;
100 	return (t);
101 }
102 
103 	/* remove thru line n of file f from storage */
104 static void
105 clrl(int f, long n)
106 {
107 	int i, j;
108 
109 	j = n-lineno[f]+1;
110 	for (i = 0; i+j < ntext[f]; i++)
111 		movstr(text[f][i+j], text[f][i]);
112 	lineno[f] = n+1;
113 	ntext[f] -= j;
114 }
115 
116 static void
117 movstr(char *s, char *t)
118 {
119 	while (*t++ = *s++)
120 		continue;
121 }
122 
123 int
124 main(int argc, char **argv)
125 {
126 	char *s0, *s1;
127 
128 	if ((argc > 1) && (*argv[1] == '-')) {
129 		argc--;
130 		argv++;
131 		while (*++argv[0])
132 			if (*argv[0] == 'b')
133 				bflag++;
134 	}
135 
136 	(void) setlocale(LC_ALL, "");
137 #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
138 #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
139 #endif
140 	(void) textdomain(TEXT_DOMAIN);
141 
142 	if (argc != 3)
143 		error(gettext("must have 2 file arguments"));
144 	file[0] = dopen(argv[1], argv[2]);
145 	file[1] = dopen(argv[2], argv[1]);
146 	for (;;) {
147 		s0 = getl(0, ++n0);
148 		s1 = getl(1, ++n1);
149 		if (s0 == NULL || s1 == NULL)
150 			break;
151 		if (cmp(s0, s1) != 0) {
152 			if (!easysynch() && !hardsynch())
153 				progerr("5");
154 		} else {
155 			clrl(0, n0);
156 			clrl(1, n1);
157 		}
158 	}
159 	/* diff is expected to return 1 if the files differ */
160 	if (s0 == NULL && s1 == NULL)
161 		return (diffFound);
162 	if (s0 == NULL) {
163 		(void) output(-1, INF);
164 		return (1);
165 	}
166 	if (s1 == NULL) {
167 		(void) output(INF, -1);
168 		return (1);
169 	}
170 	/* NOTREACHED */
171 	return (0);
172 }
173 
174 	/* synch on C successive matches */
175 static int
176 easysynch()
177 {
178 	int i, j;
179 	int k, m;
180 	char *s0, *s1;
181 
182 	for (i = j = 1; i < RANGE && j < RANGE; i++, j++) {
183 		s0 = getl(0, n0+i);
184 		if (s0 == NULL)
185 			return (output(INF, INF));
186 		for (k = C-1; k < j; k++) {
187 			for (m = 0; m < C; m++)
188 				if (cmp(getl(0, n0+i-m),
189 					getl(1, n1+k-m)) != 0)
190 					goto cont1;
191 			return (output(i-C, k-C));
192 cont1:
193 			;
194 		}
195 		s1 = getl(1, n1+j);
196 		if (s1 == NULL)
197 			return (output(INF, INF));
198 		for (k = C-1; k <= i; k++) {
199 			for (m = 0; m < C; m++)
200 				if (cmp(getl(0, n0+k-m),
201 					getl(1, n1+j-m)) != 0)
202 					goto cont2;
203 			return (output(k-C, j-C));
204 cont2:
205 			;
206 		}
207 	}
208 	return (0);
209 }
210 
211 static int
212 output(int a, int b)
213 {
214 	int i;
215 	char *s;
216 
217 	if (a < 0)
218 		change(n0-1, 0, n1, b, "a");
219 	else if (b < 0)
220 		change(n0, a, n1-1, 0, "d");
221 	else
222 		change(n0, a, n1, b, "c");
223 	for (i = 0; i <= a; i++) {
224 		s = getl(0, n0+i);
225 		if (s == NULL)
226 			break;
227 		(void) printf("< %s", s);
228 		clrl(0, n0+i);
229 	}
230 	n0 += i-1;
231 	if (a >= 0 && b >= 0)
232 		(void) printf("---\n");
233 	for (i = 0; i <= b; i++) {
234 		s = getl(1, n1+i);
235 		if (s == NULL)
236 			break;
237 		(void) printf("> %s", s);
238 		clrl(1, n1+i);
239 	}
240 	diffFound = 1;
241 	n1 += i-1;
242 	return (1);
243 }
244 
245 static void
246 change(long a, int b, long c, int d, char *s)
247 {
248 	range(a, b);
249 	(void) printf("%s", s);
250 	range(c, d);
251 	(void) printf("\n");
252 }
253 
254 static void
255 range(long a, int b)
256 {
257 	if (b == INF)
258 		(void) printf("%ld,$", a);
259 	else if (b == 0)
260 		(void) printf("%ld", a);
261 	else
262 		(void) printf("%ld,%ld", a, a+b);
263 }
264 
265 static int
266 cmp(char *s, char *t)
267 {
268 	if (debug)
269 		(void) printf("%s:%s\n", s, t);
270 	for (;;) {
271 		if (bflag && isspace(*s) && isspace(*t)) {
272 			while (isspace(*++s))
273 				;
274 			while (isspace(*++t))
275 				;
276 		}
277 		if (*s != *t || *s == 0)
278 			break;
279 		s++;
280 		t++;
281 	}
282 	return (*s-*t);
283 }
284 
285 static FILE *
286 dopen(char *f1, char *f2)
287 {
288 	FILE *f;
289 	char b[PATH_MAX], *bptr, *eptr;
290 	struct stat statbuf;
291 
292 	if (cmp(f1, "-") == 0) {
293 		if (cmp(f2, "-") == 0)
294 			error(gettext("can't do - -"));
295 		else {
296 			if (fstat(fileno(stdin), &statbuf) == -1)
297 				error(gettext("can't access stdin"));
298 			else
299 				return (stdin);
300 		}
301 	}
302 	if (stat(f1, &statbuf) == -1)
303 		error(gettext("can't access %s"), f1);
304 	if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
305 		for (bptr = b; *bptr = *f1++; bptr++)
306 			;
307 		*bptr++ = '/';
308 		for (eptr = f2; *eptr; eptr++)
309 			if (*eptr == '/' && eptr[1] != 0 && eptr[1] != '/')
310 				f2 = eptr+1;
311 		while (*bptr++ = *f2++)
312 			;
313 		f1 = b;
314 	}
315 	f = fopen(f1, "r");
316 	if (f == NULL)
317 		error(gettext("can't open %s"), f1);
318 	return (f);
319 }
320 
321 
322 static void
323 progerr(char *s)
324 {
325 	error(gettext("program error %s"), s);
326 }
327 
328 static void
329 error(char *err, ...)
330 {
331 	va_list	ap;
332 
333 	va_start(ap, err);
334 	(void) fprintf(stderr, "diffh: ");
335 	(void) vfprintf(stderr, err, ap);
336 	(void) fprintf(stderr, "\n");
337 	va_end(ap);
338 	exit(2);
339 }
340 
341 	/* stub for resychronization beyond limits of text buf */
342 static int
343 hardsynch()
344 {
345 	change(n0, INF, n1, INF, "c");
346 	(void) printf(gettext("---change record omitted\n"));
347 	error(gettext("can't resynchronize"));
348 	return (0);
349 }
350