Home | History | Annotate | Download | only in diff
      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