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], <ext[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