Metropoli BBS
VIEWER: diff.c MODE: TEXT (ASCII)
/*
 * Displays differences between two ASCII files
 *
 * Options:
 *	-d		= Inhibit display of differences
 *	-l		= Inhibit display of line numbers
 *	r=num	= Minimum # lines to re-syncronize
 *
 * Copyright 1988-1995 Dave Dunfield
 * All rights reserved.
 *
 * Permission granted for personal (non-commercial) use only.
 *
 * Compile command: cc diff -fop
 */
#include <stdio.h>

#define	LINE_SIZE	100		/* maximum size of input lines */
#define	MAX_DIFF	200		/* maximum number of different lines */

char ft1[MAX_DIFF][LINE_SIZE], ft2[MAX_DIFF][LINE_SIZE];

unsigned r1 = 0, r2 = 0, w1 = 0, w2 = 0, l1, l2;
unsigned resync = 2, diffs = 0;

char diff = -1, line = -1;

char *fn1, *fn2;
FILE *fp1, *fp2;

/*
 * Main program, compare files
 */
main(argc, argv)
	int argc;
	char *argv[];
{
	char *ptr;

	l2 = 0;
	for(l1 = 1; l1 < argc; ++l1) {
		ptr = argv[l1];
		switch((tolower(*ptr++) << 8) | tolower(*ptr++)) {
			case 'r=' :			/* minimum # lines to resync */
				resync = get_num(ptr);
				break;
			case '-d' :			/* inhibit display of differences */
				diff = 0;
				break;
			case '-l' :			/* inhibit display of line numbers */
				line = 0;
				break;
			default:			/* filename to compare */
				if(!(fp2 = fopen(fn2 = argv[l1], "r"))) {
					fprintf(stderr, "%s: Unable to open\n", fn2);
					exit(-1); }
				if(!l2++) {
					fn1 = fn2;
					fp1 = fp2; } } }

	if(l2 != 2) {
		fputs("\nUse: diff <file1> <file2> [-d -l r=#lines]\n\nCopyright 1988-1995 Dave Dunfield\nAll rights reserved.\n", stderr);
		exit(-1); }

	l1 = l2 = 1;
	for(;;) {
		fill_buffer();
		if((r1 == w1) || (r2 == w2)) {
			show_changed(w1, w2);
			if(diffs)
				fprintf(stdout,"%u differences.\n", diffs);
			else
				fprintf(stdout,"Files match exactly.\n");
			exit(diffs); }
		if(equal(ft1[r1], ft2[r2])) {
			r1 = (r1 + 1) % MAX_DIFF;
			r2 = (r2 + 1) % MAX_DIFF;
			++l1; ++l2;
			continue; }
		scan_buffer(); }
}

/*
 * Fill up the buffer with lines from the input file
 */
fill_buffer()
{
	register int j1, j2;

	while((j1 = (w1 + 1) % MAX_DIFF) != r1) {
		if(!fgets(ft1[w1], LINE_SIZE, fp1))
			break;
		w1 = j1; }
	while((j2 = (w2 + 1) % MAX_DIFF) != r2) {
		if(!fgets(ft2[w2], LINE_SIZE, fp2))
			break;
		w2 = j2; }
}

/*
 * Scan the buffer looking for a pattern
 */
scan_buffer()
{
	int i, i1, i2, j1, j2;
	char flag;

	i1 = r1;
	i2 = r2;
	fill_buffer();
	do {		/* scan with this portion */
		j1 = i1;
		j2 = i2;
		do {
			flag = 0;
			if(j2 != w2) {		/* we can check this one */
				flag = -1;
				if(equal(ft1[i1], ft2[j2]) && (i=test_next(i1, j2))) {
					show_changed(i1, j2);
					r1 = (r1 + i) % MAX_DIFF;
					r2 = (r2 + i) % MAX_DIFF;
					l1 += i; l2 += i;
					return; }
				j2 = (j2 + 1) % MAX_DIFF; }
			if(j1 != w1) {		/* we can check this one */
				flag = -1;
				if(equal(ft1[j1], ft2[i2]) && (i=test_next(j1, i2))) {
					show_changed(j1, i2);
					r1 = (r1 + i) % MAX_DIFF;
					r2 = (r2 + i) % MAX_DIFF;
					l1 += i; l2 += i;
					return; }
				j1 = (j1 + 1) % MAX_DIFF; } }
		while(flag);
		if(i1 != w1) {		/* More lines in buffer */
			i1 = (i1 + 1) % MAX_DIFF;
			flag = -1; }
		if(i2 != w2) {		/* More lines in buffer */
			i2 = (i2 + 1) % MAX_DIFF;
			flag = -1; } }
	while(flag);

/* Cannot accept any more data into buffers, check for overflow */
	if((((w1 + 1) % MAX_DIFF) == r1) || (((w2 + 1) % MAX_DIFF) == r2)) {
		fprintf(stdout,"Differences to great at  %u < > %u\n", l1, l2);
		exit(-1); }
/* Buffers not full, must be end of file */
	show_changed(w1, w2);
}

/*
 * Test that the next "resync" entries match
 */
test_next(i1, i2)
	unsigned i1, i2;
{
	int i;

	for(i=1; i < resync; ++i) {
		i1 = (i1 + 1) % MAX_DIFF;
		i2 = (i2 + 1) % MAX_DIFF;
		if((i1 == w1) || (i2 == w2))
			return i;
		if(!equal(ft1[i1], ft2[i2]))
			return 0; }
	return i;
}

/*
 * Display the changed lines & reset read pointers
 */
show_changed(i1, i2)
	unsigned i1, i2;
{
	if((r1 != i1) || (r2 != i2)) {
		++diffs;
		if(line)
			fprintf(stdout,"*** %s(%u) < > %s(%u) ***\n", fn1, l1, fn2, l2);
		while(r1 != i1) {
			++l1;
			if(diff)
				fprintf(stdout,"<%s\n", ft1[r1]);
			r1 = (r1 + 1) % MAX_DIFF; }
		while(r2 != i2) {
			++l2;
			if(diff)
				fprintf(stdout,">%s\n", ft2[r2]);
			r2 = (r2 + 1) % MAX_DIFF; } }
}

/*
 * Get a decimal number from the command line
 */
get_num(string)
	char *string;
{
	register unsigned value;
	register char chr;

	value = 0;
	while(isdigit(chr = *string++))
		value = (value * 10) + (chr - '0');

	if(chr) {
		fputs("DIFF: Invalid number\n", stderr);
		exit(-1); }

	return	value;
}

/*
 * Test for two strings equal
 */
equal(str1, str2)
	char *str1, *str2;
{
	register char c;

	while((c = *str1++) == *str2++) {
		if(!c)
			return 1; }
	return 0;
}
[ RETURN TO DIRECTORY ]