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