xref: /titanic_51/usr/src/cmd/diff/diffh.c (revision eaacacc0c33d7b79a8156d9b3e07dbb4354eb2d6)
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  #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  	return (0);
174  }
175  
176  	/* synch on C successive matches */
177  static int
178  easysynch()
179  {
180  	int i, j;
181  	int k, m;
182  	char *s0, *s1;
183  
184  	for (i = j = 1; i < RANGE && j < RANGE; i++, j++) {
185  		s0 = getl(0, n0+i);
186  		if (s0 == NULL)
187  			return (output(INF, INF));
188  		for (k = C-1; k < j; k++) {
189  			for (m = 0; m < C; m++)
190  				if (cmp(getl(0, n0+i-m),
191  					getl(1, n1+k-m)) != 0)
192  					goto cont1;
193  			return (output(i-C, k-C));
194  cont1:
195  			;
196  		}
197  		s1 = getl(1, n1+j);
198  		if (s1 == NULL)
199  			return (output(INF, INF));
200  		for (k = C-1; k <= i; k++) {
201  			for (m = 0; m < C; m++)
202  				if (cmp(getl(0, n0+k-m),
203  					getl(1, n1+j-m)) != 0)
204  					goto cont2;
205  			return (output(k-C, j-C));
206  cont2:
207  			;
208  		}
209  	}
210  	return (0);
211  }
212  
213  static int
214  output(int a, int b)
215  {
216  	int i;
217  	char *s;
218  
219  	if (a < 0)
220  		change(n0-1, 0, n1, b, "a");
221  	else if (b < 0)
222  		change(n0, a, n1-1, 0, "d");
223  	else
224  		change(n0, a, n1, b, "c");
225  	for (i = 0; i <= a; i++) {
226  		s = getl(0, n0+i);
227  		if (s == NULL)
228  			break;
229  		(void) printf("< %s", s);
230  		clrl(0, n0+i);
231  	}
232  	n0 += i-1;
233  	if (a >= 0 && b >= 0)
234  		(void) printf("---\n");
235  	for (i = 0; i <= b; i++) {
236  		s = getl(1, n1+i);
237  		if (s == NULL)
238  			break;
239  		(void) printf("> %s", s);
240  		clrl(1, n1+i);
241  	}
242  	diffFound = 1;
243  	n1 += i-1;
244  	return (1);
245  }
246  
247  static void
248  change(long a, int b, long c, int d, char *s)
249  {
250  	range(a, b);
251  	(void) printf("%s", s);
252  	range(c, d);
253  	(void) printf("\n");
254  }
255  
256  static void
257  range(long a, int b)
258  {
259  	if (b == INF)
260  		(void) printf("%ld,$", a);
261  	else if (b == 0)
262  		(void) printf("%ld", a);
263  	else
264  		(void) printf("%ld,%ld", a, a+b);
265  }
266  
267  static int
268  cmp(char *s, char *t)
269  {
270  	if (debug)
271  		(void) printf("%s:%s\n", s, t);
272  	for (;;) {
273  		if (bflag && isspace(*s) && isspace(*t)) {
274  			while (isspace(*++s))
275  				;
276  			while (isspace(*++t))
277  				;
278  		}
279  		if (*s != *t || *s == 0)
280  			break;
281  		s++;
282  		t++;
283  	}
284  	return (*s-*t);
285  }
286  
287  static FILE *
288  dopen(char *f1, char *f2)
289  {
290  	FILE *f;
291  	char b[PATH_MAX], *bptr, *eptr;
292  	struct stat statbuf;
293  
294  	if (cmp(f1, "-") == 0) {
295  		if (cmp(f2, "-") == 0)
296  			error(gettext("can't do - -"));
297  		else {
298  			if (fstat(fileno(stdin), &statbuf) == -1)
299  				error(gettext("can't access stdin"));
300  			else
301  				return (stdin);
302  		}
303  	}
304  	if (stat(f1, &statbuf) == -1)
305  		error(gettext("can't access %s"), f1);
306  	if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
307  		for (bptr = b; *bptr = *f1++; bptr++)
308  			;
309  		*bptr++ = '/';
310  		for (eptr = f2; *eptr; eptr++)
311  			if (*eptr == '/' && eptr[1] != 0 && eptr[1] != '/')
312  				f2 = eptr+1;
313  		while (*bptr++ = *f2++)
314  			;
315  		f1 = b;
316  	}
317  	f = fopen(f1, "r");
318  	if (f == NULL)
319  		error(gettext("can't open %s"), f1);
320  	return (f);
321  }
322  
323  
324  static void
325  progerr(char *s)
326  {
327  	error(gettext("program error %s"), s);
328  }
329  
330  static void
331  error(char *err, ...)
332  {
333  	va_list	ap;
334  
335  	va_start(ap, err);
336  	(void) fprintf(stderr, "diffh: ");
337  	(void) vfprintf(stderr, err, ap);
338  	(void) fprintf(stderr, "\n");
339  	va_end(ap);
340  	exit(2);
341  }
342  
343  	/* stub for resychronization beyond limits of text buf */
344  static int
345  hardsynch()
346  {
347  	change(n0, INF, n1, INF, "c");
348  	(void) printf(gettext("---change record omitted\n"));
349  	error(gettext("can't resynchronize"));
350  	return (0);
351  }
352