xref: /illumos-gate/usr/src/cmd/diff/diffh.c (revision 29267a9d01e87d9c5d871a7bb863719d89a51281)
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