home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Phoenix CD 2.0
/
Phoenix_CD.cdr
/
15a
/
diff24.zip
/
DIFF.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-11-29
|
36KB
|
925 lines
/*----------------------------------------------------------------------------
diff.c -- file compare and change bar inserter for text files
originally produced by D Krantz, modified for Turbo C by P van Es
date 4/19/88
5/2/88 v1.1 options have been UNIX-fied
5/4/88 v1.2 comparisons made faster
bugs corrected
upper case handling rationalised
6/14/88 v2.0 automatic resync feature added
6/18/88 v2.1 screen listing switchable
6/20/88 v2.2 resync made faster for small changes
6/21/88 v2.3 resync checksum lookup added
11/25/88 v2.4 by Ricky Lively:
when either file reaches EOF,
shows remaining and unmatched lines in both files.
change checksum to crc.
add absolute text line counter.
add text line length.
increase text line size from 83 to 255.
add -l minimum comparison column.
add -m maximum comparison column.
add -e tab expansion.
add -i ignore all white space.
add -t trim eol white space.
add version number to help.
change text to test line, to preserve white space, case, etc.
save position of text lines and reposition to print.
clean up warnings and includes.
---------------------------------------------------------------------------*/
/* file difference utility */
#if !defined (__COMPACT__)
#error Must be compiled with COMPACT model
#endif
#include <ctype.h>
#include <stdio.h>
#include <process.h> /* exit */
#include <string.h> /* strcmp, stricmp, strcpy */
#include <stdlib.h> /* malloc, free, atoi */
typedef unsigned char byte;
#define OPT_FLAG '-' /* command line switch recogniser */
#define MAXLINE 256 /* maximum input line characters */
#define FORMFEED 'L'-'@'
#define EOF_REACHED 0 /* eof during resync */
#define RE_SYNCED 1 /* we managed to re-sync */
#define NO_SYNC 2 /* no sync but no eof either */
#define VERSION "v2.4 11/25/88" /* version number */
struct LINE /* structure defining line internally */
{ int lineanum; /* what line in file */
int linenum; /* what line on page */
int pagenum; /* what page */
int length; /* length of text line */
byte crc; /* use crc for quick comparison */
struct LINE *prev; /* pointer to previous line */
struct LINE *link; /* linked list pointer */
struct LINE *same; /* pointer to next line with crc */
char test[MAXLINE]; /* text of line for testing */
long position; /* position in file of text line */
};
typedef struct LINE *line_ptr;
typedef FILE *FILE_PTR;
struct LINE root[3]; /* root of internal linked list */
int linea_count[3] = {1,1,1}; /* file's absolute line counter */
int line_count[3] = {1,1,1}; /* file's line counter */
int page_count[3] = {1,1,1}; /* file's page counter */
int command_errors = 0; /* number of command line errors */
char xx1[132], /* space for file names */
xx2[132];
int files = 0; /* nr of files in command line */
char *infile_name[3] = {NULL,xx1,xx2};
char outfile_name[132]; /* output file name */
FILE_PTR infile[3]; /* input file pointers */
FILE *outfile; /* changebarred output file ptr */
static line_ptr at[3] = {NULL, &(root[1]), &(root[2])};
static line_ptr same_crc[256][2];
char text[MAXLINE]; /* text of line */
int debug = 0; /* trace switch */
int trace_enabled = 0; /* keyboard tracing switch */
int bar_col = 78; /* column for change bar */
int right_col = MAXLINE - 1; /* maximum column to compare up to */
int left_col = 0; /* minimum column to compare from */
int top_skip = 0; /* lines to skip at top of page */
int bot_skip = 0; /* lines to skip at bottom of page */
int page_len = 66; /* length of a page */
int up_case = 0; /* boolean - ignore case */
int re_sync = 3; /* lines that must match for resync */
int output = 0; /* boolean - change barred outfile on */
int blanks = 0; /* boolean - blank lines significant */
int skip1 = 0; /* pages in first file to skip */
int skip2 = 0; /* pages in second file to skip */
int scr_on = 1; /* screen listing turned on */
int tabs = 1; /* boolean - expand tabs to spaces */
int white = 0; /* boolean - ignore white space */
int trim = 0; /* boolean - trim off trailing white */
static int crctab[] = /* CRC lookup table */
{ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
#if 0 /* trace & other debug functions off */
#include <conio.h> /* kbhit, getch */
#include <alloc.h> /* coreleft */
#define trace( x ) callstack( x )
#define ret { callpop(); return; }
#define ret_val( x ) { callpop(); return( x ); }
#define TRACER_FUNCTIONS
#else
#define trace( x ) /* nothing */
#define ret { return; }
#define ret_val( x ) { return( x ); }
#endif
/*--------------------------------------------------------------------------*/
#ifdef TRACER_FUNCTIONS
char *names[20];
int stack = 0;
int
callstack(
char *str )
{ int i;
names[stack++] = str;
if( debug )
{ for( i = 0; i < stack; i++ )
printf( " " );
printf( "Entering %s\n", str );
}
if( trace_enabled && kbhit() )
{ switch( getch() )
{ case 't':
case 'T': debug = !debug;
break;
case 's':
case 'S': printf( "\n------------" );
for( i = stack - 1; i >= 0; i-- )
printf( "\n%s", names[i] );
printf( "\n------------\n" );
printf( "free: %lu\n", coreleft() );
break;
default: break;
} }
return;
}
int
callpop(
void )
{ int i;
if( debug )
{ for( i = 0; i < stack; i++ )
printf( " " );
printf( "Exiting %s\n", names[stack - 1] );
}
stack--;
return;
}
#endif
int
dont_look(
line_ptr line )
/* tells us whether or not this line should be considered for comparison or
* is a filler (eg header, blank) line
*/
{ register int i;
trace( "dont_look" );
if( line == NULL ) /* EOF reached */
ret_val( 0 );
if( line->linenum <= top_skip )
ret_val( 1 );
if( line->linenum > page_len - bot_skip )
ret_val( 1 );
if( !blanks )
{ for( i = 0; i < MAXLINE; i++ )
switch( line->test[i] )
{ case '\0':
case '\n': ret_val( 1 );
case '\t':
case ' ' : break;
default : ret_val( 0 );
} }
ret_val( 0 );
}
int
equal(
line_ptr a,
line_ptr b )
/* tells us if the pointers 'a' and 'b' point to line buffers containing
* equivalent text or not
*/
{ trace( "equal" );
if(( a == NULL ) || ( b == NULL ))
ret_val( 0 );
if( a->crc != b->crc )
ret_val( 0 );
if(( a->length < left_col ) || /* are lines shorter than left column */
( b->length < left_col ))
ret_val( 1 );
if( up_case )
ret_val( !strncmp( &( a->test[left_col] ),
&( b->test[left_col] ),
right_col - left_col ))
else
ret_val( !strnicmp( &( a->test[left_col] ),
&( b->test[left_col] ),
right_col - left_col ))
}
int
position(
int f,
line_ptr where )
/* moves the input pointer for file 'f' such that the next line to be read
* will be 'where'
*/
{ trace( "position" );
at[f] = &root[f];
if( where == NULL )
ret;
while( at[f]->link != where )
at[f] = at[f]->link;
ret;
}
int
addcrc( /* update a CRC check */
int crc, /* running CRC value */
unsigned char c ) /* character to add */
/* CRC computation logic
The logic for this method of calculating the CRC 16 bit polynomial
is taken from an article by David Schwaderer in the April 1985
issue of PC Tech Journal.
*/
{ return(( crc >> 8 ) & 0x00ff ) ^ crctab[( crc ^ c ) & 0x00ff];
}
void
makecrc(
line_ptr a )
/* calculates a crc for the line, and stores it in the line buffer. This
* allows for faster comparisons
*/
{ register int i;
register int j;
register int cs;
trace( "makecrc" );
cs = 0;
if( a->length > right_col ) /* set length of compare to min of */
j = right_col; /* right_col or line length */
else
j = a->length;
if( a->length < left_col ) /* is line shorter than left column */
i = j; /* set while terminate immediately */
else
i = left_col;
while( i < j )
cs = addcrc( cs, a->test[i++] );
a->crc = ( byte ) cs;
}
void
tabexpand( /* expand tabs to spaces */
char *s1,
char *s2 )
{ register int i;
register char j;
trace( "tabexpand" );
for( i = j = 0; s2[i]; i++ )
{ if( s2[i] != '\t' )
{ s1[j++] = s2[i];
continue;
}
do s1[j++] = ' ';
while( j % 8 != 0 );
}
s1[j] = 0;
}
void
nowhite( /* ignore white space */
char *s1,
char *s2 )
{ register int i,
j;
trace( "nowhite" );
for( i = j = 0; s2[i]; i++ )
{ if( s2[i] != ' ' && s2[i] != '\t' )
s1[j++] = s2[i];
}
s1[j] = 0;
}
void
trimline( /* trim off trailing white space */
char *s1 )
{ register int i;
trace( "trimline" );
i = strlen( s1 );
if( s1[--i] == '\n' ) /* if linefeed last char, skip */
--i;
for( ; s1[i] == ' ' || s1[i] == '\t'; i-- )
;
s1[++i] = '\n'; /* assume linefeed should be last char*/
s1[++i] = '\0'; /* end string after linefeed */
}
line_ptr
next_line(
int f )
/* allocates, links and returns the next line from file 'f' if no lines are
* buffered, otherwise returns the next buffered line from 'f' and updates the
* link pointer to the next buffered line; it also inserts the line in the
* correct place in the array same_crc
*/
{ line_ptr place_hold,
start;
char buffer[MAXLINE];
trace( "next_line" );
if( at[f]->link != NULL )
{ at[f] = at[f]->link;
ret_val( at[f] );
}
else
{ at[f]->link = ( line_ptr ) malloc( sizeof( struct LINE ));
if( at[f]->link == NULL )
{ printf( "\nError: Out of Memory" );
exit (2);
}
place_hold = at[f];
at[f] = at[f]->link;
if( place_hold == &( root[f] ))
at[f]->prev = NULL;
else
at[f]->prev = place_hold;
at[f]->link = NULL;
at[f]->same = NULL;
at[f]->position = ftell( infile[f] );
if( fgets( at[f]->test, MAXLINE, infile[f] ) == NULL )
{ free( at[f] );
at[f] = place_hold;
at[f]->link = NULL;
at[f]->same = NULL;
ret_val( NULL );
}
if( white != 0 )
{ nowhite( buffer, at[f]->test );
strcpy( at[f]->test, buffer );
}
else
{ if( trim != 0 )
trimline( at[f]->test );
if( tabs != 0 )
{ tabexpand( buffer, at[f]->test );
strcpy( at[f]->test, buffer );
} }
if( up_case )
strupr( at[f]->test );
at[f]->length = strlen( at[f]->test );
makecrc( at[f] ); /* calc crc for new text line */
#ifdef EMBEDDED_FORMFEEDS
if(( strchr( at[f]->test, FORMFEED ) != NULL ) ||
( line_count[f] > page_len ))
#else
if(( *(at[f]->test ) == FORMFEED ) ||
( line_count[f] > page_len ))
#endif
{ page_count[f]++;
line_count[f] = 1;
}
at[f]->lineanum = linea_count[f]++;
at[f]->linenum = line_count[f]++;
at[f]->pagenum = page_count[f];
if( !dont_look( at[f] )) /* insert in array unless dont_look */
{ start = same_crc[at[f]->crc][f - 1];
if( start == NULL )
same_crc[at[f]->crc][f - 1] = at[f];
else
{ while( start->same != NULL )
start = start->same;
start->same = at[f]; /* start NULL now, insert at[f] here */
} }
ret_val( at[f] );
} }
int
discard (
int f,
line_ptr to )
/* deallocates all buffered lines from the root up to and including 'to' for
* file 'f', including from same_crc
*/
{ line_ptr temp;
trace( "discard" );
for(;;)
{ if( root[f].link == NULL || to == NULL )
break;
temp = root[f].link;
if( !dont_look( temp )) /* line exists, find same_crc recd */
same_crc[temp->crc][f - 1] = temp->same; /* replace with temp->same */
root[f].link = root[f].link->link;
root[f].link->prev = NULL;
free( temp );
if( temp == to )
break;
}
at[f] = &root[f];
ret;
}
int
getline(
char text[], /* text string to return */
int file, /* file number to read */
long position ) /* position of line to read */
/* go back to file and get the original line for output.
*/
{ long before; /* marker to return to after read */
trace( "getline" );
before = ftell( infile[file] );
fseek( infile[file], position, SEEK_SET );
fgets( text, MAXLINE, infile[file] );
fseek( infile[file], before, SEEK_SET );
ret;
}
int
put(
line_ptr line )
/* if change barred output file is turned on, prints all lines from the root
* of file 1 up to and including 'line'. This is only called if a match exists
* for each significant line in file 2.
*/
{ line_ptr temp;
trace( "put" );
if( output )
for( temp = root[1].link; ; )
{ if( temp == NULL )
ret;
getline( text, 1, temp->position );
fputs( text, outfile );
if( temp == line )
ret;
temp = temp->link;
}
ret;
}
char
*change_bar(
char *str )
/* inserts a change bar into the text pointed to by 'str' and returns a
* pointer to 'str'
*/
{ int i;
char temp[MAXLINE + 1],
*dest,
*base;
trace( "change_bar" );
base = str;
dest = temp;
i = 0;
if( bar_col != 0 )
{ for( i = 0; *str != '\n'; i++ )
{ if(( *str == '\r' ) && ( *( str + 1 ) != '\n' ))
i = 0;
*( dest++ ) = *( str++ );
}
while( i++ < bar_col )
*( str )++ = ' ';
strcpy( str, "|\n" );
}
else
{ if( str[0] != ' ' )
{ strcpy( temp, str );
strcpy( str + 1, temp );
}
str[0] = '|';
}
ret_val( base );
}
int
added(
line_ptr line )
/* prints a change summary for all significant lines from the root of file 1
* up to and including 'line'. If output is enabled, adds a change bar to the
* text and outputs the line to the output file
*/
{ line_ptr temp;
trace( "added" );
for( temp = root[1].link; ; )
{ if( temp == NULL )
ret;
getline( text, 1, temp->position );
if( !dont_look( temp ) && scr_on )
printf( "%.3d:%.2d(%.4d)< %s", temp->pagenum,
temp->linenum,
temp->lineanum,
text );
if( output )
if( dont_look( temp ))
fputs( text, outfile );
else
fputs( change_bar( text ), outfile );
if( temp == line )
ret;
temp = temp->link;
} }
int
deleted(
line_ptr line )
/* outputs a change summary for all lines in file 2 from the root up to and
* including 'line'
*/
{ line_ptr temp;
trace( "deleted" );
for( temp = root[2].link; ; )
{ if( temp == NULL )
ret;
getline( text, 2, temp->position );
if( !dont_look( temp ) && scr_on )
printf( "%.3d:%.2d(%.4d)> %s", temp->pagenum,
temp->linenum,
temp->lineanum,
text );
if( temp == line )
ret;
temp = temp->link;
} }
int
resync(
line_ptr first,
line_ptr second,
int lookahead )
/* resynchronizes file 1 and file 2 after a difference is detected and
* outputs changed lines and change summaries via added() and deleted().
* Exits with the file inputs pointing at the next two lines that match,
* unless it is impossible to sync up again, in which case all lines in file 1
* are printed via added(). Deallocates lines printed by this function.
*/
{ line_ptr file1_start,
file2_start,
last_bad1,
last_bad2,
t1,
t2,
crc;
int i,
k,
moved1,
moved2;
trace( "resync" );
position( 2, second ); /* ensure enough lines in memory */
last_bad2 = second;
for( k = 0; k < lookahead && last_bad2 != NULL ; k++ )
last_bad2 = next_line( 2 );
moved1 = 0; /* now reset file pointers */
file1_start = first;
position( 1, first );
for( k = 0; k < lookahead; k++ )
{ while( dont_look( file1_start = next_line( 1 )))
;
if( file1_start == NULL )
goto no_sy;
moved2 = 0;
crc = same_crc[file1_start->crc][1]; /* see if any matching line at all */
while( crc != NULL )
{ while( !equal( crc, file1_start )) /* look for matching entries */
{ crc = crc->same;
if( crc == NULL )
break;
}
if( crc != NULL )
{ t1 = file1_start; /* ok we have a hit */
file2_start = crc;
t2 = file2_start;
position( 1, file1_start );
position( 2, file2_start );
for( i = 0; ( i < re_sync ) && equal( t1, t2 ); i++ )
{ while( dont_look( t1 = next_line( 1 )))
;
while( dont_look( t2 = next_line( 2 )))
;
if(( t1 == NULL ) || ( t2 == NULL ))
break;
}
if( i == re_sync )
{ moved2++;
if(( last_bad2 = file2_start->prev ) == NULL )
moved2 = 0;
goto synced;
}
crc = crc->same; /* get next entry */
} }
last_bad1 = file1_start; /* else no sync/match yet, loop list */
position( 1, file1_start );
while( dont_look( file1_start = next_line( 1 )))
;
moved1++;
}
ret_val( NO_SYNC );
no_sy:
position( 1, first);
while(( first = next_line( 1 )) != NULL )
{ added( first );
discard( 1, first );
}
ret_val( EOF_REACHED );
synced:
if( moved1 )
{ added( last_bad1 );
discard( 1, last_bad1 );
}
position( 1, file1_start );
if( moved2 )
{ deleted( last_bad2 );
discard( 2, last_bad2 );
}
position( 2, file2_start );
if( scr_on )
printf( "\n" );
ret_val( RE_SYNCED );
}
diff(
void )
/* differencing executive. Prints and deallocates all lines up to where a
* difference is detected, at which point resync() is called. Exits on end of
* file 1
*/
{ int look_lines,
result;
line_ptr first,
second;
trace( "diff" );
for( ;; )
{ while( dont_look( first = next_line( 1 )))
;
if( first == NULL ) /* file 1 End-of-File */
{ put( first );
while(( second = next_line( 2 )) != NULL ) /* put all file 2 as deleted */
{ if( second->length > left_col ) /* only if lines are long enough */
{ deleted( second );
discard( 2, second );
} }
ret;
}
while( dont_look( second = next_line( 2 )))
;
if( equal( first, second ))
{ put( first );
discard( 1, first );
discard( 2, second );
}
else
{ look_lines = 10; /* start with 10 lines look-ahead */
result = NO_SYNC;
while( result == NO_SYNC )
{ result = resync( first, second, look_lines );
look_lines *= 2;
if( look_lines == 80 ) /* when 80, assume BIG diff, set 400 */
look_lines = 400;
} }
if( second == NULL )
ret;
} }
int
page_skip(
void )
/* skips the first 'skip1' pages of file 1, and then the first 'skip2' pages
* of file 2. This is useful to jump over tables of contents
*/
{ line_ptr first,
second;
trace( "page_skip" );
for( ;; )
{ first = next_line( 1 );
if(( first == NULL ) || ( first->pagenum > skip1 ))
break;
put( first );
discard( 1, first );
}
if( first != NULL )
position( 1, first );
for( ;; )
{ second = next_line( 2 );
if(( second == NULL ) || ( second->pagenum > skip2 ))
break;
discard( 2, second );
}
if( second != NULL )
position( 2, second );
ret;
}
int
help( /* outputs usage information */
void )
{ printf( "\ndiff - text file differencer and change barrer ("
VERSION
")"
"\nusage: diff [option{option}] newfile oldfile [barfile]"
"\n"
"\noptions: (default) description" );
#ifdef TRACER_FUNCTIONS
printf( "\n -t (off) trace operation"
"\n hit keyboard t to turn off trace while executing"
"\n hit keyboard s to see memory usage" );
#endif
printf( "\n -b n (78) column of barfile for change bar"
"\n -l n (1) compare from left column n"
"\n -m n (255) compare to maximum column n"
"\n -h n (0) lines at top of each page to skip for headers"
"\n -f n (0) lines at bottom of each page to skip for footers"
"\n -p n (66) lines per page (embedded form feeds override)"
"\n -c (off) uppercase/lowercase is significant"
"\n -r n (3) lines that must match before files are considered resynced"
"\n after differences are found"
"\n -w (not) blank lines are considered significant"
"\n -s (on) screen listing off"
"\n -e (on) tab expansion to blanks off"
"\n -i (off) ignore all white space (tabs and blanks)"
"\n -t (off) trim end-of-line white space (tabs and blanks)"
"\n -n n (0) pages in NEWFILE to skip before compare (ex. table of contents)"
"\n -o n (0) pages in OLDFILE to skip before compare"
"\n");
ret;
}
int
open_files( /* opens the input and output files */
void )
{ int i;
trace( "open_files" );
for( i = 1; i < 3; i++ )
if(( infile[i] = fopen( infile_name[i], "r" )) == NULL )
{ printf( "\nError: can't open %s", infile_name[i] );
command_errors++;
}
if( files > 2 )
if(( outfile = fopen( outfile_name, "w" )) == NULL )
{ printf( "\nError: can't create %s", outfile_name );
command_errors++;
}
ret;
}
strip_opt( /* processes each command line option */
int ac,
char *av[] )
{ int i;
trace( "strip_opt" );
for( i = 1; i < ac; i++ )
{ if( av[i][0] == OPT_FLAG )
{ switch( av[i][1] )
{ case 'b': bar_col = atoi( av[++i] );
break;
case 'l': left_col = atoi( av[++i] ) - 1; /* array address, so make 0 based */
break;
case 'm': right_col = atoi( av[++i] );
break;
case 'h': top_skip = atoi( av[++i] );
break;
case 'f': bot_skip = atoi( av[++i] );
break;
case 'p': page_len = atoi( av[++i] );
break;
case 'c': up_case = 1;
break;
case 'r': re_sync = atoi( av[++i] );
break;
case 'w': blanks = 1;
break;
case 's': scr_on = 0;
break;
case 'e': tabs = 0;
break;
case 'i': white = 1;
break;
case 't': trim = 1;
break;
case 'n': skip1 = atoi( av[++i] );
break;
case 'o': skip2 = atoi( av[++i] );
break;
#ifdef TRACER_FUNCTIONS
case 't': trace_enabled = debug = 1;
break;
#endif
default: printf( "\nUnrecognised option %s", av[i] );
command_errors++;
} }
else
{ switch( files )
{ case 0: strcpy( infile_name[1], av[i] );
break;
case 1: strcpy( infile_name[2], av[i] );
break;
case 2: strcpy( outfile_name, av[i] );
output = 1;
break;
default: printf( "\nError: too many files at %s", av[i] );
command_errors++;
}
files++;
} }
if( !scr_on && !output )
{ printf( "\nError: no output file or screen listing will be generated." );
command_errors++;
}
ret;
}
int
main(
int argc,
char *argv[] )
{ trace ( "main" );
if( argc == 1 )
{ help();
exit( 0 );
}
else
printf( "Pag:Ln Line# diff -- "
VERSION
"\n" );
strip_opt (argc, argv);
if( files < 2 )
{ printf( "\nError: Must specify two files" );
exit( 2 );
}
open_files();
if( command_errors )
exit( 2 );
at[1]->prev = NULL; /* set root previous pointers to 0 */
at[2]->prev = NULL;
page_skip();
diff();
added( NULL ); /* print out all from file 1 */
deleted( NULL ); /* print out all from file 2 */
ret;
}