293 lines
4.9 KiB
C
Executable File
293 lines
4.9 KiB
C
Executable File
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#ident "@(#)diffh.c 1.10 95/03/22 SMI" /* SVr4.0 1.3 */
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <locale.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <limits.h>
|
|
|
|
#define C 3
|
|
#define RANGE 30
|
|
#define LEN 255
|
|
#define INF 16384
|
|
|
|
char *text[2][RANGE];
|
|
long lineno[2] = {1, 1}; /* no. of 1st stored line in each file */
|
|
int ntext[2]; /* number of stored lines in each */
|
|
long n0, n1; /* scan pointer in each */
|
|
int bflag;
|
|
int debug = 0;
|
|
FILE *file[2];
|
|
|
|
/* return pointer to line n of file f */
|
|
char *
|
|
getl(f, n)
|
|
long n;
|
|
{
|
|
register char *t;
|
|
register delta, nt;
|
|
|
|
again:
|
|
delta = n - lineno[f];
|
|
nt = ntext[f];
|
|
if (delta < 0)
|
|
progerr("1");
|
|
if (delta < nt)
|
|
return (text[f][delta]);
|
|
if (delta > nt)
|
|
progerr("2");
|
|
if (nt >= RANGE)
|
|
progerr("3");
|
|
if (feof(file[f]))
|
|
return (NULL);
|
|
t = text[f][nt];
|
|
if (t == 0) {
|
|
t = text[f][nt] = (char *)malloc(LEN+1);
|
|
if (t == NULL)
|
|
if (hardsynch())
|
|
goto again;
|
|
else
|
|
progerr("5");
|
|
}
|
|
t = fgets(t, LEN, file[f]);
|
|
if (t != NULL)
|
|
ntext[f]++;
|
|
return (t);
|
|
}
|
|
|
|
/* remove thru line n of file f from storage */
|
|
clrl(f, n)
|
|
long n;
|
|
{
|
|
register i, j;
|
|
|
|
j = n-lineno[f]+1;
|
|
for (i = 0; i+j < ntext[f]; i++)
|
|
movstr(text[f][i+j], text[f][i]);
|
|
lineno[f] = n+1;
|
|
ntext[f] -= j;
|
|
}
|
|
|
|
movstr(s, t)
|
|
register char *s, *t;
|
|
{
|
|
while (*t++ = *s++)
|
|
continue;
|
|
}
|
|
|
|
main(argc, argv)
|
|
char **argv;
|
|
{
|
|
char *s0, *s1;
|
|
|
|
FILE *dopen();
|
|
if (*argv[1] == '-') {
|
|
argc--;
|
|
argv++;
|
|
while (*++argv[0])
|
|
if (*argv[0] == 'b')
|
|
bflag++;
|
|
}
|
|
|
|
(void) setlocale(LC_ALL, "");
|
|
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
|
|
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
|
|
#endif
|
|
(void) textdomain(TEXT_DOMAIN);
|
|
|
|
if (argc != 3)
|
|
error("must have 2 file arguments", "");
|
|
file[0] = dopen(argv[1], argv[2]);
|
|
file[1] = dopen(argv[2], argv[1]);
|
|
for (;;) {
|
|
s0 = getl(0, ++n0);
|
|
s1 = getl(1, ++n1);
|
|
if (s0 == NULL || s1 == NULL)
|
|
break;
|
|
if (cmp(s0, s1) != 0) {
|
|
if (!easysynch() && !hardsynch())
|
|
progerr("5");
|
|
} else {
|
|
clrl(0, n0);
|
|
clrl(1, n1);
|
|
}
|
|
}
|
|
if (s0 == NULL && s1 == NULL)
|
|
return;
|
|
if (s0 == NULL)
|
|
output(-1, INF);
|
|
if (s1 == NULL)
|
|
output(INF, -1);
|
|
}
|
|
|
|
/* synch on C successive matches */
|
|
easysynch()
|
|
{
|
|
int i, j;
|
|
register k, m;
|
|
char *s0, *s1;
|
|
|
|
for (i = j = 1; i < RANGE && j < RANGE; i++, j++) {
|
|
s0 = getl(0, n0+i);
|
|
if (s0 == NULL)
|
|
return (output(INF, INF));
|
|
for (k = C-1; k < j; k++) {
|
|
for (m = 0; m < C; m++)
|
|
if (cmp(getl(0, n0+i-m),
|
|
getl(1, n1+k-m)) != 0)
|
|
goto cont1;
|
|
return (output(i-C, k-C));
|
|
cont1:
|
|
;
|
|
}
|
|
s1 = getl(1, n1+j);
|
|
if (s1 == NULL)
|
|
return (output(INF, INF));
|
|
for (k = C-1; k <= i; k++) {
|
|
for (m = 0; m < C; m++)
|
|
if (cmp(getl(0, n0+k-m),
|
|
getl(1, n1+j-m)) != 0)
|
|
goto cont2;
|
|
return (output(k-C, j-C));
|
|
cont2:
|
|
;
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
output(a, b)
|
|
{
|
|
register i;
|
|
char *s;
|
|
|
|
if (a < 0)
|
|
change(n0-1, 0, n1, b, "a");
|
|
else if (b < 0)
|
|
change(n0, a, n1-1, 0, "d");
|
|
else
|
|
change(n0, a, n1, b, "c");
|
|
for (i = 0; i <= a; i++) {
|
|
s = getl(0, n0+i);
|
|
if (s == NULL)
|
|
break;
|
|
printf("< %s", s);
|
|
clrl(0, n0+i);
|
|
}
|
|
n0 += i-1;
|
|
if (a >= 0 && b >= 0)
|
|
printf("---\n");
|
|
for (i = 0; i <= b; i++) {
|
|
s = getl(1, n1+i);
|
|
if (s == NULL)
|
|
break;
|
|
printf("> %s", s);
|
|
clrl(1, n1+i);
|
|
}
|
|
n1 += i-1;
|
|
return (1);
|
|
}
|
|
|
|
change(a, b, c, d, s)
|
|
long a, c;
|
|
char *s;
|
|
{
|
|
range(a, b);
|
|
printf("%s", s);
|
|
range(c, d);
|
|
printf("\n");
|
|
}
|
|
|
|
range(a, b)
|
|
long a;
|
|
{
|
|
if (b == INF)
|
|
printf("%ld,$", a);
|
|
else if (b == 0)
|
|
printf("%ld", a);
|
|
else
|
|
printf("%ld,%ld", a, a+b);
|
|
}
|
|
|
|
cmp(s, t)
|
|
char *s, *t;
|
|
{
|
|
if (debug)
|
|
printf("%s:%s\n", s, t);
|
|
for (;;) {
|
|
if (bflag && isspace(*s) && isspace(*t)) {
|
|
while (isspace(*++s))
|
|
;
|
|
while (isspace(*++t))
|
|
;
|
|
}
|
|
if (*s != *t || *s == 0)
|
|
break;
|
|
s++;
|
|
t++;
|
|
}
|
|
return (*s-*t);
|
|
}
|
|
|
|
FILE *
|
|
dopen(f1, f2)
|
|
char *f1, *f2;
|
|
{
|
|
FILE *f;
|
|
char b[PATH_MAX], *bptr, *eptr;
|
|
struct stat statbuf;
|
|
if (cmp(f1, "-") == 0)
|
|
if (cmp(f2, "-") == 0)
|
|
error("can't do - -", "");
|
|
else
|
|
return (stdin);
|
|
if (stat(f1, &statbuf) == -1)
|
|
error("can't access ", f1);
|
|
if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
|
|
for (bptr = b; *bptr = *f1++; bptr++)
|
|
;
|
|
*bptr++ = '/';
|
|
for (eptr = f2; *eptr; eptr++)
|
|
if (*eptr == '/' && eptr[1] != 0 && eptr[1] != '/')
|
|
f2 = eptr+1;
|
|
while (*bptr++ = *f2++)
|
|
;
|
|
f1 = b;
|
|
}
|
|
f = fopen(f1, "r");
|
|
if (f == NULL)
|
|
error("can't open", f1);
|
|
return (f);
|
|
}
|
|
|
|
|
|
progerr(s)
|
|
char *s;
|
|
{
|
|
error("program error ", s);
|
|
}
|
|
|
|
error(s, t)
|
|
char *s, *t;
|
|
{
|
|
fprintf(stderr, "diffh: %s%s\n", gettext(s), t);
|
|
exit(1);
|
|
}
|
|
|
|
/* stub for resychronization beyond limits of text buf */
|
|
hardsynch()
|
|
{
|
|
change(n0, INF, n1, INF, "c");
|
|
printf(gettext("---change record omitted\n"));
|
|
error("can't resynchronize", "");
|
|
return (0);
|
|
}
|