#include "bdscio.h" #include "dio.h" /* * Program to compare (byte for byte) * two files and print differences * * to build: (without dio) * cc fc * ll fc * to build: (with dio) * cc fc * ll fc dio * to use: * fc master.fil check.fil [-a] [-b] * or * fc * * for instructions * * H.Moran 10/27/79 * Revision History -- tested under BDS C ver. 1.50 * ---------------- * 2/13/80 slight mod * 8/6/81 add bin8() and bin16() * 7/9/82 modify format of comments indents, types, etc * modify display format slightly * 7/16/83 spacer lines at matches, split mismatch field * 10/9/83 minor documentation cleanup, add directed i/o */ #define END_FILE -1 /* end of file marker returned by getc() */ #define END_TEXT 0x1A /* ascii end of file mark */ #define NO_FILE -1 /* no such file indication given by fopen() */ #define FILE struct _buf #define PROC int /* PROCedure i.e. function returning no value */ #define BOOL int /* Boolean i.e. YES or NO */ #define YES 1 #define NO 0 #define MICROSHELL NO /* MicroShell will NOT do the directed i/o */ /* * Collect File names and options * open files * invoke file compare */ PROC main(argc, argv) int argc; char *argv[]; { int ascii; unsigned start_adrs, htoi(); char *ptr; FILE mstbuf, *mbufp; FILE chkbuf, *cbufp; #if (! MICROSHELL) dioinit(&argc, argv); #endif mbufp = &mstbuf; cbufp = &chkbuf; ascii = NO; /* assign the defaults */ start_adrs = 0; if( argc < 3 || argc > 5 ) /* Illegal invocation */ bummer(); else if( fopen(argv[1], mbufp) == NO_FILE ) printf("No such file %s\n", argv[1]); else if( fopen(argv[2], cbufp) == NO_FILE) printf("No such file %s\n", argv[2]); else { while( argc > 3 ) { ptr = argv[--argc]; if( *ptr++ != '-' ) bummer(); switch ( tolower(*ptr++) ) { case 'a': ascii = YES; break; case 'b': start_adrs = htoi(ptr); break; default: puts("Unrecognized option. Aborted\n\n"); bummer(); } /* end switch */ } /* end while */ fcompare(mbufp, cbufp, start_adrs, ascii); } /* end else */ #if (! MICROSHELL) dioflush(); #endif } /* * compare 2 files and print their differences * on the console */ PROC fcompare(mfile, cfile, adrs, ascii) FILE *mfile; /* the input file buffer */ FILE *cfile; /* the output file buffer */ unsigned adrs; /* the address of begin of file */ BOOL ascii; /* flag of whether these are ascii files */ { char *bin8(), *bin16(); int mc, cc; /* 1 char buffers */ BOOL had_err; /* flag that an error has occurred */ BOOL prev_matched; /* flag that the previous comparison matched */ char *xl(); /* function to translate control chars */ char str1[6], str2[6]; /* temporaries for strings */ prev_matched = had_err = NO; while( !((mc=getc(mfile)) == END_FILE || (ascii && mc == END_TEXT)) ) { if( (cc=getc(cfile)) == END_FILE || ( ascii && cc == END_TEXT )) { puts("Checkfile shorter than Master file\n"); return; } else if( mc != cc ) { if ( prev_matched ) { printf("\n"); prev_matched = NO; } if( ! had_err ) { had_err = YES; puts("\nRelative Master Check"); puts("\nAddress File File Mismatch"); puts("\n------- ---- ---- --------\n"); } /* end if */ if( ascii ) { printf("%04x %-4s %-4s %s\n", adrs, xl(mc, str1), xl(cc, str2), bin8(mc^cc)); } else { printf("%04x %02x = %-4s %02x = %-4s %s\n", adrs, mc, xl(mc, str1), cc, xl(cc, str2), bin8(mc^cc)); } } /* end else if */ else prev_matched = YES; adrs++; } /* end while */ if( ! ((cc=getc(cfile)) == END_FILE || (ascii && cc == END_TEXT)) ) puts("Masterfile shorter than checkfile\n"); } /* end fcompare() */ /* * Print a message then exit to CP/M */ PROC err_exit(msg) char *msg; { exit(puts(msg)); } /* * Convert ASCII hex string to integer */ unsigned htoi(string) char *string; { unsigned number; char c; number = 0; c = tolower(*string++); while( isalpha(c) || isdigit(c) ) { if( c > 'f' ) return (number); number *= 16; if( isdigit(c) ) number += c -'0'; else number += c - 'a' + 10; c = tolower(*string++); } return (number); } /* * Print the invocation syntax error message * and exit to CP/M */ PROC bummer() { puts("Correct invocation form is:\n"); puts(" FC [-a -b]\n\n"); puts("Where optional arguments are:\n\n"); puts("-a => these are ascii files (terminate on 1A Hex)\n"); puts("-b => begin of file is address "); puts("default is 0\n"); exit(1); } /* * Translate the char argument c into a * 4 char string in xlate[] * If c is a printable ascii char its * translation is itself right blank padded * Else if c is a standard control char its * translation is a string identifying that * control char Else its translation is "????" */ char * xl(c, xlate) int c; char *xlate; { if( c > 0x7f || c < 0 ) strcpy(xlate, "????"); else if( c == 0x7f ) strcpy(xlate, "del "); else if( c > 0x1f ) { /* then it is printable */ xlate[0] = c; strcpy(xlate+1, " "); } else switch (c) { case 0x7: strcpy(xlate, "bel"); break; case 0x8: strcpy(xlate, "bs"); break; case 0x9: strcpy(xlate, "tab"); break; case 0xa: strcpy(xlate, "lf"); break; case 0xc: strcpy(xlate, "ff"); break; case 0xd: strcpy(xlate, "cr"); break; case 0x1b: strcpy(xlate, "esc"); break; default: xlate[0] = '^'; /* show control chars as */ xlate[1] = c + 0x40; /* ^ e.g. ^A is */ xlate[2] = '\0'; /* control A */ break; } return (xlate); } /* * return a pointer to a string of 8 binary digits * representing the value of the input argument u */ char * bin8(u) char u; { char i; char *fakeout, *f; f = fakeout = "???? ????"; for ( i = 0; i < 4; i++ ) { *f++ = (u & 0x80) ? '1' : '0'; u = u << 1; } ++f; for ( ; i < 8; ++i ) { *f++ = (u & 0x80) ? '1' : '0'; u = u << 1; } return (fakeout); } /* * return a pointer to an ascii string of 16 binary digits * representing the value of the value of the input argument */ char * bin16(u) unsigned u; { int i; char *fakeout, *f; f = fakeout = "????????????????"; for ( i = 0; i < 16; i++ ) { *f++ = (u & 0x8000) ? '1' : '0'; u = u << 1; } return (fakeout); }