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 /*
32  * Copyright 2006-2016 J. Schilling
33  *
34  * @(#)diffh.c	1.13 16/11/06 J. Schilling
35  */
36 #if defined(sun)
37 #pragma ident "@(#)diffh.c 1.13 16/11/06 J. Schilling"
38 #endif
39 
40 #if defined(sun)
41 #pragma ident	"@(#)diffh.c	1.20	05/07/22 SMI"
42 #endif
43 
44 #ifdef	SCHILY_BUILD
45 
46 #include <schily/mconfig.h>
47 #include <schily/stdio.h>
48 #include <schily/stdlib.h>
49 #include <schily/unistd.h>
50 #include <schily/ctype.h>
51 #include <schily/nlsdefs.h>
52 #include <schily/types.h>
53 #include <schily/stat.h>
54 #include <schily/utypes.h>	/* limits.h */
55 #include <schily/varargs.h>
56 #include <schily/schily.h>
57 #define	error	errorh
58 #include <schily/maxpath.h>
59 
60 #ifndef	PATH_MAX
61 #ifdef	MAXPATHNAME
62 #define	PATH_MAX	MAXPATHNAME
63 #endif
64 #endif
65 #ifndef	PATH_MAX
66 #define	PATH_MAX	1024
67 #endif
68 
69 #else	/* non-portable SunOS -only definitions BEGIN */
70 
71 #define	_FILE_OFFSET_BITS	64
72 #define	_LARGEFILE_SOURCE
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <unistd.h>
76 #include <ctype.h>
77 #include <locale.h>
78 #include <sys/types.h>
79 #include <sys/stat.h>
80 #include <limits.h>
81 #include <stdarg.h>
82 
83 #define	HAVE_SETVBUF
84 #define	PROTOTYPES
85 #define	__PR(a)	a
86 #define	EXPORT
87 #define	LOCAL	static
88 
89 #define	Uchar	unsigned char
90 #define	Llong	long long
91 
92 #endif	/* non-portable SunOS -only definitions END */
93 
94 #define	C		3
95 #define	RANGE		30
96 #define	INF		16384
97 
98 char *text[2][RANGE];		/* Line pointers */
99 size_t ltext[2][RANGE];		/* Sizes for line pointers */
100 off_t lineno[2] = {1, 1};	/* no. of 1st stored line in each file */
101 int ntext[2];			/* number of stored lines in each */
102 off_t n0, n1;			/* scan pointer in each */
103 int bflag;
104 int debug = 0;
105 FILE *file[2];
106 static int diffFound = 0;
107 
108 static char *getln __PR((int f, off_t n));
109 static void clrl __PR((int f, off_t n));
110 static void movstr __PR((char *s, char *t));
111 	int main __PR((int argc, char **argv));
112 static int easysynch __PR((void));
113 static int output __PR((int a, int b));
114 static void change __PR((off_t a, int b, off_t c, int d, char *s));
115 static void range __PR((off_t a, int b));
116 static int cmp __PR((char *s, char *t));
117 static FILE *dopen __PR((char *f1, char *f2));
118 static void progerr __PR((char *s));
119 static void error __PR((char *err, ...));
120 static int hardsynch __PR((void));
121 
122 	/* return pointer to line n of file f */
123 static char *
getln(f,n)124 getln(f, n)
125 	int	f;
126 	off_t	n;
127 {
128 	char *t;
129 	off_t delta, nt;
130 	ssize_t	s;
131 
132 again:
133 	delta = n - lineno[f];
134 	nt = ntext[f];
135 	if (delta < 0)
136 		progerr("1");
137 	if (delta < nt)
138 		return (text[f][delta]);
139 	if (delta > nt)
140 		progerr("2");
141 	if (nt >= RANGE)
142 		progerr("3");
143 	if (feof(file[f]))
144 		return (NULL);
145 
146 	s = getdelim(&text[f][nt], &ltext[f][nt], '\n', file[f]);
147 	t = text[f][nt];
148 	if (s == -1 && t == NULL) {
149 		if (hardsynch())
150 			goto again;
151 		else
152 			progerr("5");
153 	}
154 
155 	if (s == -1)
156 		t = NULL;
157 	if (t != NULL)
158 		ntext[f]++;
159 	return (t);
160 }
161 
162 	/* remove thru line n of file f from storage */
163 static void
clrl(f,n)164 clrl(f, n)
165 	int	f;
166 	off_t	n;
167 {
168 	int i, j;
169 
170 	j = n-lineno[f]+1;
171 	for (i = 0; i+j < ntext[f]; i++) {
172 		if (ltext[f][i+j] < ltext[f][i]) {
173 			ltext[f][i+j] = ltext[f][i];
174 			text[f][i+j] = realloc(text[f][i+j], ltext[f][i+j]);
175 			if (text[f][i+j] == NULL)
176 				progerr("5");
177 		}
178 		movstr(text[f][i+j], text[f][i]);
179 	}
180 	lineno[f] = n+1;
181 	ntext[f] -= j;
182 }
183 
184 static void
movstr(s,t)185 movstr(s, t)
186 	char	*s;
187 	char	*t;
188 {
189 	while ((*t++ = *s++) != '\0')
190 		continue;
191 }
192 
193 int
main(argc,argv)194 main(argc, argv)
195 	int	argc;
196 	char	**argv;
197 {
198 	char *s0, *s1;
199 
200 	if ((argc > 1) && (*argv[1] == '-')) {
201 		argc--;
202 		argv++;
203 		while (*++argv[0])
204 			if (*argv[0] == 'b')
205 				bflag++;
206 	}
207 
208 	(void) setlocale(LC_ALL, "");
209 #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
210 #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
211 #endif
212 	(void) textdomain(TEXT_DOMAIN);
213 
214 	if (argc != 3)
215 		error(gettext("must have 2 file arguments"));
216 	file[0] = dopen(argv[1], argv[2]);
217 	file[1] = dopen(argv[2], argv[1]);
218 	for (;;) {
219 		s0 = getln(0, ++n0);
220 		s1 = getln(1, ++n1);
221 		if (s0 == NULL || s1 == NULL)
222 			break;
223 		if (cmp(s0, s1) != 0) {
224 			if (!easysynch() && !hardsynch())
225 				progerr("5");
226 		} else {
227 			clrl(0, n0);
228 			clrl(1, n1);
229 		}
230 	}
231 	/* diff is expected to return 1 if the files differ */
232 	if (s0 == NULL && s1 == NULL)
233 		return (diffFound);
234 	if (s0 == NULL) {
235 		(void) output(-1, INF);
236 		return (1);
237 	}
238 	if (s1 == NULL) {
239 		(void) output(INF, -1);
240 		return (1);
241 	}
242 	/* NOTREACHED */
243 	return (0);
244 }
245 
246 	/* synch on C successive matches */
247 static int
easysynch()248 easysynch()
249 {
250 	int i, j;
251 	int k, m;
252 	char *s0, *s1;
253 
254 	for (i = j = 1; i < RANGE && j < RANGE; i++, j++) {
255 		s0 = getln(0, n0+i);
256 		if (s0 == NULL)
257 			return (output(INF, INF));
258 		for (k = C-1; k < j; k++) {
259 			for (m = 0; m < C; m++)
260 				if (cmp(getln(0, n0+i-m),
261 					getln(1, n1+k-m)) != 0)
262 					goto cont1;
263 			return (output(i-C, k-C));
264 cont1:
265 			;
266 		}
267 		s1 = getln(1, n1+j);
268 		if (s1 == NULL)
269 			return (output(INF, INF));
270 		for (k = C-1; k <= i; k++) {
271 			for (m = 0; m < C; m++)
272 				if (cmp(getln(0, n0+k-m),
273 					getln(1, n1+j-m)) != 0)
274 					goto cont2;
275 			return (output(k-C, j-C));
276 cont2:
277 			;
278 		}
279 	}
280 	return (0);
281 }
282 
283 static int
output(a,b)284 output(a, b)
285 	int	a;
286 	int	b;
287 {
288 	int i;
289 	char *s;
290 
291 	if (a < 0)
292 		change(n0-1, 0, n1, b, "a");
293 	else if (b < 0)
294 		change(n0, a, n1-1, 0, "d");
295 	else
296 		change(n0, a, n1, b, "c");
297 	for (i = 0; i <= a; i++) {
298 		s = getln(0, n0+i);
299 		if (s == NULL)
300 			break;
301 		(void) printf("< %s", s);
302 		clrl(0, n0+i);
303 	}
304 	n0 += i-1;
305 	if (a >= 0 && b >= 0)
306 		(void) printf("---\n");
307 	for (i = 0; i <= b; i++) {
308 		s = getln(1, n1+i);
309 		if (s == NULL)
310 			break;
311 		(void) printf("> %s", s);
312 		clrl(1, n1+i);
313 	}
314 	diffFound = 1;
315 	n1 += i-1;
316 	return (1);
317 }
318 
319 static void
change(a,b,c,d,s)320 change(a, b, c, d, s)
321 	off_t	a;
322 	int	b;
323 	off_t	c;
324 	int	d;
325 	char	*s;
326 {
327 	range(a, b);
328 	(void) printf("%s", s);
329 	range(c, d);
330 	(void) printf("\n");
331 }
332 
333 static void
range(a,b)334 range(a, b)
335 	off_t	a;
336 	int	b;
337 {
338 	if (b == INF)
339 		(void) printf("%lld,$", (Llong)a);
340 	else if (b == 0)
341 		(void) printf("%lld", (Llong)a);
342 	else
343 		(void) printf("%lld,%lld", (Llong)a, (Llong)a+b);
344 }
345 
346 static int
cmp(s,t)347 cmp(s, t)
348 	char	*s;
349 	char	*t;
350 {
351 	if (debug)
352 		(void) printf("%s:%s\n", s, t);
353 	for (;;) {
354 		if (bflag && isspace((Uchar)*s) && isspace((Uchar)*t)) {
355 			while (isspace((Uchar)*++s))
356 				;
357 			while (isspace((Uchar)*++t))
358 				;
359 		}
360 		if (*s != *t || *s == 0)
361 			break;
362 		s++;
363 		t++;
364 	}
365 	return (*s-*t);
366 }
367 
368 static FILE *
dopen(f1,f2)369 dopen(f1, f2)
370 	char	*f1;
371 	char	*f2;
372 {
373 	FILE *f;
374 	char b[PATH_MAX], *bptr, *eptr;
375 	struct stat statbuf;
376 
377 	if (cmp(f1, "-") == 0) {
378 		if (cmp(f2, "-") == 0)
379 			error(gettext("can't do - -"));
380 		else {
381 			if (fstat(fileno(stdin), &statbuf) == -1)
382 				error(gettext("can't access stdin"));
383 			else
384 				return (stdin);
385 		}
386 	}
387 	if (stat(f1, &statbuf) == -1)
388 		error(gettext("can't access %s"), f1);
389 	if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
390 		for (bptr = b; (*bptr = *f1++) != '\0'; bptr++)
391 			;
392 		*bptr++ = '/';
393 		for (eptr = f2; *eptr; eptr++)
394 			if (*eptr == '/' && eptr[1] != 0 && eptr[1] != '/')
395 				f2 = eptr+1;
396 		while ((*bptr++ = *f2++) != '\0')
397 			;
398 		f1 = b;
399 	}
400 	f = fopen(f1, "r");
401 	if (f == NULL)
402 		error(gettext("can't open %s"), f1);
403 #ifdef	HAVE_SETVBUF
404 	setvbuf(f, NULL, _IOFBF, 8*1024);
405 #endif
406 	return (f);
407 }
408 
409 
410 static void
progerr(s)411 progerr(s)
412 	char	*s;
413 {
414 	error(gettext("program error %s"), s);
415 }
416 
417 #ifdef	PROTOTYPES
418 static void
error(char * err,...)419 error(char *err, ...)
420 #else
421 static void
422 error(err, va_alist)
423 	char	*err;
424 	va_dcl
425 #endif
426 
427 {
428 	va_list	ap;
429 
430 #ifdef	PROTOTYPES
431 	va_start(ap, err);
432 #else
433 	va_start(ap);
434 #endif
435 #ifdef	SCHILY_PRINT
436 	(void) fprintf(stderr, "diffh: %r\n", err, ap);
437 #else
438 	(void) fprintf(stderr, "diffh: ");
439 	(void) vfprintf(stderr, err, ap);
440 	(void) fprintf(stderr, "\n");
441 #endif
442 	va_end(ap);
443 	exit(2);
444 }
445 
446 	/* stub for resychronization beyond limits of text buf */
447 static int
hardsynch()448 hardsynch()
449 {
450 	change(n0, INF, n1, INF, "c");
451 	(void) printf(gettext("---change record omitted\n"));
452 	error(gettext("can't resynchronize"));
453 	return (0);
454 }
455