/*
bdiff.c - Byte Difference: diff two almost identical files.
This program is used to display the bytes changed between two files. The
files are assumed to be the same length. The bytes from the first (changed)
file are displayed first, followed by the bytes from the second (original)
file, in square brackets. Bytes that are printable (ASCII) are displayed as
characters enclosed in quotes (a quote itself is duplicated).
Jason Hood, 7 September, 1998.
Public Domain.
981228: display the changed filename, or optionally the original filename;
if one or two bytes are identical within a difference, include them
in the diff list.
000222: stop diffing if too different; display message if identical.
000303: changed message if too different.
001001: split difference across lines;
option to disable string translation.
v1.00, 15 & 16 October, 2003:
better handling of different sized files;
display the count if diff is too big;
surround the filename in quotes if it contains spaces.
v1.01, 7 September, 2004:
use a buffer to store the different bytes;
increase default maximum to 88 bytes;
line up the last line of a multi-line diff;
require four printable characters before using a string;
calculate the lengths of both files, use the smaller;
modified return codes.
*/
#define PVERS "1.01"
#define PDATE "7 September, 2004"
#include
#include
#include
#include
#ifdef __DJGPP__
void __crt0_load_environment_file( char* dummy ) { }
char** __crt0_glob_function( char* dummy ) { return 0; }
#endif
int string = 1; // Display strings
int calculate_len( unsigned char* buf, int len );
int display( unsigned char* buf, int len );
enum
{
E_SAME, // Files are identical
E_DIFF, // Files are different
E_TOO, // Files are too different
E_OPT, // Unknown/invalid option
E_MEM, // Not enough memory for buffer
E_NEW, // Unable to open changed file
E_OLD, // Unable to open original file
};
int main( int argc, char* argv[] )
{
FILE* file1; // Changed file
FILE* file2; // Original file
long offset; // Offset of difference
int byte1, byte2; // The two bytes
char* buf1; // Changed bytes
char* buf2; // Original bytes
char* disp1; // Changed bytes being displayed
char* disp2; // Original bytes being displayed
int len; // Length of difference
int cnt1, cnt2; // Length of difference to display
int maxlen = 88; // Stop diffing if length exceeds this
int out = 1; // Filename to display
int different = E_SAME; // Were any differences found?
if (argc < 3 || strcmp( argv[1], "/?" ) == 0 ||
strcmp( argv[1], "-?" ) == 0 ||
strcmp( argv[1], "--help" ) == 0)
{
puts(
"BDiff by Jason Hood .\n"
"Version "PVERS" ("PDATE"). Public Domain.\n"
"http://misc.adoxa.cjb.net/\n"
"\n"
"Display the byte difference between two almost-identical files.\n"
"\n"
"bdiff [-o] [-b] [-] \n"
"\n"
" -o display original filename, not changed\n"
" -b bytes only (no strings)\n"
" - no more than n bytes should differ (default is 88)"
);
return 0;
}
while (argv[1][0] == '-')
{
switch (argv[1][1])
{
case 'o': out = 2; break;
case 'b': string = 0; break;
default:
maxlen = (int)strtol( argv[1] + 1, NULL, 0 );
if (maxlen == 0)
{
fprintf( stderr, "Unknown option: %s\n", argv[1] );
return E_OPT;
}
break;
}
++argv; --argc;
}
if ((buf1 = malloc( maxlen * 2 )) == NULL)
{
fputs( "Not enough memory.\n", stderr );
return E_MEM;
}
buf2 = buf1 + maxlen;
if ((file1 = fopen( argv[1], "rb" )) == NULL)
{
fprintf( stderr, "%s: unable to open.\n", argv[1] );
return E_NEW;
}
if ((file2 = fopen( argv[2], "rb" )) == NULL)
{
fprintf( stderr, "%s: unable to open.\n", argv[2] );
return E_OLD;
}
fputs( "File: ", stdout );
if (strchr( argv[out], ' ' ) == NULL)
puts( argv[out] );
else
printf( "\"%s\"\n", argv[out] );
for (;;)
{
do // Skip identical bytes
{
byte1 = getc( file1 );
byte2 = getc( file2 );
} while (byte1 == byte2 && byte1 != EOF);
if ((byte1 | byte2) == EOF)
break;
different = E_DIFF;
offset = ftell( file1 ) - 1; // Pointing at byte after first diff.
printf( "%06lX:", offset );
len = 0; // Count the different bytes
for (;;)
{
++len;
byte1 = getc( file1 );
byte2 = getc( file2 );
if ((byte1 | byte2) == EOF)
break;
if (byte1 == byte2)
{
byte1 = getc( file1 );
byte2 = getc( file2 );
if ((byte1 | byte2) == EOF)
break;
if (byte1 == byte2)
{
byte1 = getc( file1 );
byte2 = getc( file2 );
if (byte1 == byte2 || (byte1 | byte2) == EOF)
break;
++len;
}
++len;
}
}
if (len > maxlen)
{
printf( " Difference is too great! (%d bytes found.)\n", len );
return E_TOO;
}
fseek( file1, offset, SEEK_SET );
fseek( file2, offset, SEEK_SET );
fread( buf1, len, 1, file1 );
fread( buf2, len, 1, file2 );
for (disp1 = buf1, disp2 = buf2; ; disp1 += cnt1, disp2 += cnt1)
{
cnt1 = calculate_len( disp1, len );
cnt2 = calculate_len( disp2, len );
if (cnt2 < cnt1)
cnt1 = cnt2;
cnt2 = display( disp1, cnt1 ); // Display changed bytes
if (cnt2 > 32)
putchar( ' ' ), putchar( ' ' );
else if (buf1 != disp1)
printf( "%*c", 43-7-1 - cnt2, ' ' );
else
putchar( '\t' );
putchar( '[' );
display( disp2, cnt1 ); // Display original bytes
puts( " ]" );
len -= cnt1;
if (len > 0)
fputs( " ", stdout ); // Seven spaces ("offset:")
else
break;
}
}
if (!different)
puts( "Files are identical." );
return different;
}
/*
Calculate the length to display. Allow for 11 bytes or 30 characters.
*/
int calculate_len( unsigned char* buf, int len )
{
int byte;
int quote = 0;
int pos = 0;
int cnt;
for (cnt = 0; len; ++cnt, --len)
{
byte = *buf++;
if (string &&
isprint( byte ) && (quote || (len >= 4 &&
isprint( buf[0] ) && isprint( buf[1] ) && isprint( buf[2] ))))
{
++pos;
if (!quote)
quote = 1, pos += 2; // Space & quote
if (byte == '\"')
++pos;
}
else
{
if (quote)
quote = 0, ++pos;
pos += 3;
}
if (pos > 33 - quote)
break;
}
return cnt;
}
/*
Display len bytes from buf. Printable characters are displayed within
quotes (unless there's only one); otherwise two hexadecimal digits are
used. If the character is a quote, another quote is also displayed
(eg. """Hello,"" I said.").
Returns the number of characters written.
*/
int display( unsigned char* buf, int len )
{
int byte;
int quote = 0;
int out = 0;
for (; len; --len)
{
byte = *buf++;
if (string &&
isprint( byte ) && (quote || (len >= 4 &&
isprint( buf[0] ) && isprint( buf[1] ) && isprint( buf[2] ))))
{
if (!quote)
{
quote = 1;
putchar( ' ' );
putchar( '\"' );
out += 2;
}
putchar( byte ), ++out;
if (byte == '\"')
putchar( '\"' ), ++out;
}
else
{
if (quote)
{
putchar( '\"' ), ++out;
quote = 0;
}
out += printf( " %02X", byte );
}
}
if (quote)
putchar( '\"' ), ++out;
return out;
}
               (
geocities.com/jadoxa)