/* FCMP Binary File Compare Utility       *
 * by David Champion                      *
 *   FCMP scans two files byte by         *
 *   byte, reporting all differences      *
 *   between the two files with any       *
 *   combination of file byte number,     *
 *   block number/byte offfset, and       *
 *   byte value.  The options are all     *
 *   masked by default, but may be        *
 *   activated with the flags -n (file    *
 *   byte), -b (block/byte offset),       *
 *   and -v (byte value).                 *
 *                                        *
 * Note that this is NOT useful as a      *
 *   binary diff-like utility!            *
 *                                        *
 *   19-Sep-91: -a option added           *
 *   23-May-92: -qq suppresses everything *
 *              only if files equate      */

/* includes */
#include <dos/dos.h>
#include <stdio.h>

/* defines */
	/* flags */
#define QUIET			0x01
#define BRIEF			0x02
#define VERBOSE			0x04
#define ASCII			0x08
#define HELP			0x10
#define ULTRAQUIET		0x20

	/* intelligibility */
		/* parameters */
#define COLOR			"\033[33m"
#define PLAIN			"\033[0m"
#define QUICK			0
#define FULL			1
		/* functions */
#define EQ				!strcmp
	/* macros */
#define MAKEHEX(a)	((a)>9?(a)+55:(a)+48)

main(argc,argv)
int argc;
char *argv[];
{
int c, d, k=0, n=0;
char flags=0;
FILE *file1, *file2;

	if ((argc < 2) || (argc > 5)) Usage(argv[0],QUICK);	/* if bad syntax, show quick usage */
	for (c=1;c<argc;c++) {					/* better not to have useless variables--so use one */
								/* that's not yet serving its true purpose.         */
		if (EQ(argv[c],"-v")) flags=flags | VERBOSE;
		if (EQ(argv[c],"-a")) flags=flags | ASCII;
		if (EQ(argv[c],"-h")) flags=flags | HELP;
		if (EQ(argv[c],"-q")) flags=flags | QUIET;
		if (EQ(argv[c],"-b")) flags=flags | BRIEF;
		if (EQ(argv[c],"-qq")) flags=flags | ULTRAQUIET;
	}
	/*if (flags >= HELP) flags=HELP;*/			/* if Help flagged, nothing else allowed (strictly for */
								/* illustration; if help is flagged, it doesn't matter */
								/* what else is, since we just show help and exit.     */
	if (flags >= ASCII) flags |= VERBOSE;			/* if ASCII flagged, must have verbose also */
	if (flags >= VERBOSE) flags &= ~QUIET;			/* if Verbose flagged, can't have Quiet too */
	if (flags >= ULTRAQUIET) flags |= QUIET;		/* if ultraquiet, gotta be quiet too */

	if ((flags & HELP) == HELP) Usage(argv[0],FULL);	/* if Help set, display full usage */

	if ((file1 = fopen(argv[argc-2], "r")) == NULL) NoOpen(argv[argc-2]);
	if ((file2 = fopen(argv[argc-1], "r")) == NULL) {
		fclose(file1);
		NoOpen(argv[argc-1]);
	}

	if ((flags & ULTRAQUIET) != ULTRAQUIET) {
		printf("%s simple file compare utility by D. Champion.\n",argv[0]);
		printf("Scanning %s against %s...\n",argv[argc-2],argv[argc-1]);
	}

	while (((c=getc(file1)) != EOF) && ((d=getc(file2)) != EOF)) {
		if ( SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C ) {
			printf("\nUser break.\n");
			break;
		}
		if (c != d) {
			if ((flags & QUIET) != QUIET) {	/* Quiet flag not set */
				printf("\nMismatch found at file byte %d",k);
				if ((flags & BRIEF) != BRIEF)	/* Brief flag not set */
						 printf(" (block %d, offset %d)",k/512+1,k%512);
				if ((flags & VERBOSE) == VERBOSE) {	/* Verbose flag set */
						printf(" \t: %c%c",MAKEHEX(c/16),MAKEHEX(c%16));
						if ((flags & ASCII) == ASCII)	/* ASCII representation */
								printf(" %c",c);
						printf(" : %c%c",MAKEHEX(d/16),MAKEHEX(d%16));
						if ((flags & ASCII) == ASCII)	/* ASCII representation */
								printf(" %c",d);
				}
			}
			n++;
		}
		k++;
	}

	fclose(file1);
	fclose(file2);
	if ((flags & ULTRAQUIET) != ULTRAQUIET) printf("\n%d bytes checked, %d differences found.\n",k,n);
	else printf("Files not equal.\n");
}

Usage(myname,degree)
int degree;
char *myname;
{
	printf("Usage: %s [-h] | [ [-v [-a] | -q | -qq] [-b] file1 file2 ]\n",myname);
	if (degree) {
		printf("       "COLOR"%s"PLAIN" reports any differences between "COLOR"file1"PLAIN
				" and "COLOR"file2"PLAIN"\n",myname);
		printf("       \tto the limit of the shorter of the two files.\n");
		printf("       Options:\n");
		printf("       \t"COLOR"-h"PLAIN"  help:\tthis display\n");
		printf("       \t"COLOR"-v"PLAIN"  verbose:\tshow hexadecimal diffs\n");
		printf("       \t"COLOR"-a"PLAIN"  ASCII:\tshow ascii character too\n");
		printf("       \t"COLOR"-q"PLAIN"  quiet:\tshow only post-scan totals\n");
		printf("       \t"COLOR"-qq"PLAIN" ultraquiet:\tshow nothing if equal\n");
		printf("       \t"COLOR"-b"PLAIN"  brief:\tshow only byte numbers\n");
		printf("       When mutually exclusive options are requested, priority is given\n");
		printf("       \tto the one listed first in the syntax line above:\n");
		printf("       \t   %s -v -b -q src.bak src   -->   %s -v -b src.bak src\n",myname,myname);
		printf("       \t   %s -q -h copy orig        -->   %s -h\n",myname,myname);
	}
	exit(5);
}

NoOpen(name)
char *name;
{
	printf("Can't open file %s for input.\n",name);
	exit (10);
}
