home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
filedocs
/
fildif.arc
/
FILDIF.C
next >
Wrap
Text File
|
1988-06-03
|
20KB
|
813 lines
#define VERSION "1.0"
/* FILDIF - SOURCE FILE DIFFERENCES LISTING */
/*
Author: Dennis B. Ruggles
Orion Data Resources
PO box 3110
Manchester, NH 03105
(603) 622-2865
Original SRCDIF modified by B.Eiben DEC Marlboro
to compare two FILES.IDX [single line per file directories]
of the SIMTEL archives and generate the 'rough' command-files
to 'delete' superceded and 'get' new files.
Compilation via Turbo-C.
*/
/*
The following includes and defines are specifi-
cally for Microsoft's C compiler and library
*/
#include "stdio.h"
#include "stdlib.h"
#include "dos.h"
#define index strchr
#define alloc malloc
/* #define coreleft _memavl */
#define movcmdln( to ) { struct SREGS sregs;\
segread( &sregs );\
movedata( _psp, 0x80, sregs.ds, to, 128 );\
}
#define blockmv( dest, src, count ) (memcpy( dest, src, count ))
/* -------------------- END Microsoft specifics -------------------- */
#define TRUE 1
#define FALSE 0
char *USAGE[] ={
"\n Simtel File-Compare (Version ", VERSION, ")\n"
,"\n\
Usage: FILDIF FILES.IDX(old) FILES.NEW(new FILES.IDX)\n"
,"\n\
Creates files DELFILES.CMD [Files to be first DELETED]\n\
GETFILES.CMD [Files to be 'gotten']\n"
,"\n\
Both .CMD files have to be edited for system specific commands!!\n"
,NULL
};
char CUR_DEFAULT[] = "\n Current defaults are /D%d /C%d /B%d /W -%s";
char ON[] = "on";
char OFF[] = "off";
#define NUM_CMP 1 /* no. of equal lines ending a difference area */
#define MIN_DISP 0 /* no. of lines to display prior to differences */
#define MIN_BUF 64 /* min size of internal buffer in 128 byte units */
int num_disp = MIN_DISP;
int num_cmp = NUM_CMP;
unsigned int num_buf = MIN_BUF;
int white_space = FALSE;
#define FORWARD 1 /* direction for stepping LINE pointers */
#define BACKWARD -1
/* error messages */
char CANT_OPEN[] = " CANNOT BE OPENED";
/* address of command buffer for parsing switches */
char CMD_BUF[ 128 ];
/* structure of a line in the line buffers */
typedef struct{
int num_prev; /* no. of chars in previous line */
int num_this; /* no. of chars in this line */
unsigned line_num; /* line counter */
char line[1]; /* first char of variable length line */
} LINE;
/* typed functions */
FILE *fopen();
char *fgets();
char *alloc();
long int ftell();
LINE *step_inx();
char *p_non_white();
unsigned int chrpos();
unsigned int coreleft();
/* LINE pointers */
LINE *lines[2]; /* pointers to the two line arrays */
LINE *l_end[2]; /* pointers to the ends of the two arrays */
LINE *l_inx[2]; /* pointers to current last lines in the arrays */
LINE *c_inx[2]; /* pointers to the two lines being compared */
LINE *e_dif[2]; /* pointers to end of current difference area */
/* flags and counters */
char eof[2]= { FALSE, FALSE }; /* end of file flags for the two files */
char differences = 0; /* count of number of difference areas found */
/* command line arguments */
int argc;
char **argv;
/* for readability of this program: */
#define file1 0
#define file2 1
/* file pointers returned by C-library "fopen" */
FILE *file[4];
/* MAIN PROGRAM */
/*-----------------------------------------*/
main( c, v) int c; char *v[];
/*-----------------------------------------*/
{
argc = c; /* move arguments to global definitions */
argv = v;
movcmdln( CMD_BUF );
get_switches(); /* parse switches (if any) */
open_files();
/* Title line and statment of current option settings */
printf( "\nFILDIF creating DELFILES.CMD and GETFILES.CMD from %s and %s\n"
, argv[1]
, argv[2]
);
/* printf( " (Option settings: /D%d /C%d /B%d /W -%s)\n"
* , num_disp
* , num_cmp
* , num_buf
* , (white_space ? ON : OFF)
* );
*/
printf( " Version %s\n\n", VERSION );
assign_buffers(); /* grab memory for buffers */
compare_files(); /* do the file comparisons */
/* output a summary report */
if( differences )
printf( "\n%d DIFFERENCES FOUND BETWEEN %s AND %s\n"
, differences
, argv[ 1 ]
, argv[ 2 ]
);
else
printf( "\nFILES %s AND %s ARE THE SAME.\n"
, argv[ 1 ]
, argv[ 2 ]
);
if( white_space )
printf( "(MULTIPLE SPACES, TABS, FORM-FEEDS, BLANK LINES IGNORED)\n" );
exit(0);
}
/* COMPARE_FILES */
/*---------------------*/
compare_files()
/*---------------------*/
{
/* keep going until we run completely out of text */
while( more_lines( file1 ) /* fill buffer with file1 data */
| more_lines( file2 ) /* fill buffer with file2 data */
){
do{ /* compare the buffers line-by-line */
check_abort(); /* Operator had enough of this ? */
if( ! cmp_line( &c_inx[ file1 ]->line, &c_inx[ file2 ]->line ) ){
/* if a line doesn't compare */
find_differences(); /* find the difference area */
display_differences(); /* and display it. */
differences += 1; /* count the difference areas */
}
else{
/* bump comparison index for each equal line */
c_inx[ file1 ] = step_inx( c_inx[ file1 ], FORWARD );
c_inx[ file2 ] = step_inx( c_inx[ file2 ], FORWARD );
}
/* until the end of one of the buffers comes up */
}while( (c_inx[ file1 ] != l_inx[ file1 ])
&& (c_inx[ file2 ] != l_inx[ file2 ])
);
}
}
/* STEP_INX, MORE_LINES, COMPRESS */
/*-------------------------------------------------------*/
LINE *step_inx( l, direc ) register LINE *l; int direc;
/*-------------------------------------------------------*/
{ static int add_amount;
switch( direc ){
case FORWARD: /* step a LINE pointer forward */
add_amount = (l->num_this);
add_amount += (add_amount ? /* don't step if NULL */
(sizeof( LINE ) - 1)
: 0
);
break;
case BACKWARD: /* step a LINE pointer backward */
add_amount = -(l->num_prev);
add_amount -= (add_amount ? /* don't step if NULL */
(sizeof( LINE ) - 1)
: 0
);
break;
}
(char *)l = (char *)(l) + add_amount;
return( l ); /* return new pointer */
}
/*--------------------------------*/
more_lines( f ) register int f;
/*--------------------------------*/
{ static int got_more;
got_more = compress( f ); /* make room for more data */
return (got_more | read_lines( f )); /* and read it in. */
}
/*------------------------------*/
compress( f ) register int f;
/*------------------------------*/
{ static LINE *mark;
static int num_chars, move_distance;
static int i;
/* move data in buffer down to make room */
mark = c_inx[ f ]; /* everything prior to c_inx is equal */
/* also preserve the requested number of equal lines to display */
for( i=0; i < num_disp; ++i )
mark = step_inx ( mark, BACKWARD );
/* now move the data down */
num_chars = ( (char *)(l_inx[ f ]) - (char *)(mark) ) + sizeof( LINE );
move_distance = ( (char *)(mark) - (char *)(lines[ f ]) );
blockmv( lines[ f ], mark, num_chars );
/* reset our pointers to our moved data */
(char *)l_inx[ f ] = (char *)(l_inx[ f ]) - move_distance;
(char *) c_inx[ f ] = (char *)(c_inx[ f ]) - move_distance;
lines[ f ]->num_prev = 0; /* first line has no previous */
return move_distance;
}
/* READ_LINES */
/*--------------------------------*/
read_lines( f ) register int f;
/*--------------------------------*/
{ static LINE *next_line; static long file_pos; static int size_left;
static int line_size; static int got_some; static int i;
static unsigned line_num;
line_num = l_inx[ f ]->line_num;
got_some = FALSE;
/*
keep reading as long as there is input data and enough
room left for a LINE structure containing two characters
(e.g. "\n\0") followed by a LINE structure consisting
of one null character (for l_inx)
*/
while( (! eof[ f ])
&& ( (size_left = (char *)(l_end[ f ])
- (char *)(&l_inx[ f ]->line)
- sizeof( LINE )
) > 1
)
){
check_abort();
/* remember where we are in case next line goes beyond end */
file_pos = ftell( file[ f ] );
/* get next line */
if( eof[ f ] = ( (fgets( &l_inx[ f ]->line, size_left, file[ f ] )
) == NULL
)
)
break; /* unless none */
/* calculate the number of characters in the line */
l_inx[ f ]->num_this
= line_size
= chrpos( &l_inx[ f ]->line, '\0' );
/* make sure the line fit in the size_left */
if( l_inx[ f ]->line[ --line_size ] != '\n' ){
fseek( file[ f ], file_pos, 0 ); /* it didn't so reset */
break; /* the file pointers */
} /* to re-read it later */
l_inx[ f ]->line[ line_size ] = '\0'; /* delete the '\n' at end */
++line_num; /* count the lines */
/* If in the "ignore white space" mode - skip blank lines */
if( ! ( (white_space)
&& (*p_non_white( &l_inx[ f ]->line ) == '\0')
)
){
/* We have a new source line */
got_some = TRUE; /* set return flag to say we got data */
/* construct partial new LINE structure marking the end */
l_inx[ f ] = step_inx( l_inx[ f ], FORWARD );
l_inx[ f ]->num_prev = line_size;
}
l_inx[ f ]->line_num = line_num; /* Update line number, if changed */
}
/* clean up final l_inx LINE structure and leave */
l_inx[ f ]->num_this = 0;
l_inx[ f ]->line[0] = '\0';
return got_some;
}
/* FIND_DIFFERENCES */
/*----------------------*/
find_differences() /* determine boundaries of difference area */
/*----------------------*/
{ static int i, k, swc_0_1;
static int match;
static LINE *c_inx1_init, *c_inx2_init;
register LINE *inx1, *inx2;
more_lines( file1 ); /* get as much data as possible for use */
more_lines( file2 ); /* in determining the difference area */
/*
set a maximal difference area in case the cross compare loop is
never entered (which happens repeatedly at the end of processing
when one file is very much longer than the other)
*/
e_dif[ file1 ] = l_inx[ file1 ];
e_dif[ file2 ] = l_inx[ file2 ];
/* initialize things */
k = 1;
c_inx1_init = c_inx[ file1 ];
c_inx2_init = c_inx[ file2 ];
match = FALSE;
swc_0_1 = 0;
/*
The following loop performs a "cross-compare" on an ever-
increasing number of lines between the two files. It does
this until it gets "num_cmp" successive equal lines or
runs out of data to compare.
*/
while( ! match /* not got num_cmp equal */
&& (c_inx[ file1 ] != l_inx[ file1 ]) /* and more lines to com- */
&& (c_inx[ file2 ] != l_inx[ file2 ]) /* pare in both buffers */
){
/*
Step both c_inx's to widen the potential difference area. Also,
now that we got into the loop, set a better maximal difference
area in case we never find num_cmp equal ("match" never set TRUE)
*/
e_dif[ file1 ]
= c_inx[ file1 ]
= step_inx( c_inx[ file1 ], FORWARD );
e_dif[ file2 ]
= c_inx[ file2 ]
= step_inx( c_inx[ file2 ], FORWARD );
/* The "cross-compare": */
do{ /* twice, once with "swc_0_1" = 0, and again with it = 1 */
switch( swc_0_1 ){
case 0:
/*
set things up to compare all lines from original
c_inx[ file1 ] down to, but not including the new
c_inx[ file1 ] with the new line at c_inx[ file2]
*/
i = k; /* leaving old "k" causes the exclusion */
inx1 = c_inx1_init;
inx2 = c_inx[ file2 ];
break;
case 1:
/*
set things up to compare all lines from original
c_inx[ file2 ] down to, and this time including the
new c_inx[ file2 ] with the new line at c_inx[ file1 ]
*/
i = ++k; /* increasing "k" causes the inclusion */
inx1 = c_inx[ file1 ];
inx2 = c_inx2_init;
break;
}/* end switch( swc_0_1 ){ . . . */
/* if any single line compares, try to get a "num_cmp" match */
while( i-- ){
if( (cmp_line( &inx1->line, &inx2->line ))
&& (match = try_num_cmp( inx1, inx2 ))
)
break; /* the difference area is finally defined */
/*
after each failure on a "num_cmp" match,
step the appropriate index to the next line
*/
switch( swc_0_1 ){
case 0:
inx1 = step_inx( inx1, FORWARD );
break;
case 1:
inx2 = step_inx( inx2, FORWARD );
break;
}/* end switch( swc_0_1 ){ . . . */
}/* end while( i-- ){ . . . */
/*
flip "swc_0_1" from 0 to 1 unless we got a
"num_cmp" match or "swc_0_1" was already a 1
*/
}/* end do{ . . .*/ while( ! match && (swc_0_1 ^= 1) );
}/* end of while( ! match ){ . . . */
/* see how we got out of the above loop */
if( ! match ){ /* then we ran out of things to compare */
c_inx[ file1 ] = e_dif[ file1 ];
c_inx[ file2 ] = e_dif[ file2 ];
}
}
/* TRY_NUM_CMP */
/*---------------------------------------------------------*/
try_num_cmp( x_file1, x_file2 ) LINE *x_file1, *x_file2;
/*---------------------------------------------------------*/
{ static int i; register LINE *inx1, *inx2;
inx1 = x_file1; inx2 = x_file2;
/*
since we got here by making one comparison, the following
loop actually performs "num_cmp - 1" compares.
*/
for( i = num_cmp; --i;){
inx1 = step_inx( inx1, FORWARD );
inx2 = step_inx( inx2, FORWARD );
if( ! cmp_line( &inx1->line, &inx2->line ) )
return FALSE;
}
c_inx[ file1 ] = step_inx( inx1, FORWARD );
c_inx[ file2 ] = step_inx( inx2, FORWARD );
e_dif[ file1 ] = x_file1;
e_dif[ file2 ] = x_file2;
return TRUE;
}
/* DISPLAY_DIFFERENCES */
/*----------------------*/
display_differences() /* display a difference area */
/*----------------------*/
{ register LINE *inx;
register unsigned int this_line;
static int i;
/* for "file1" (0) and "file2" (1) : */
for( i = 0; i < 2; ++i){
inx = lines[ i ];
this_line = inx->line_num; /* Set counter to restore blank lines */
/* output a title */
/*
* printf( ":----------- line %u of %s -----------:\n"
* , this_line
* , argv[ i+1 ]
* );
*/
/* then the difference area */
for( ; inx != e_dif[ i ]; inx = step_inx( inx, FORWARD ) ){
while( this_line++ != inx->line_num ) /* Restore any blank lines */
printf( "\n" );
check_abort();
fprintf(file[i+3],"%s\n", &inx->line );
}
}
/* mark the end of the difference area */
/*
* printf(">>****************************************<<\n\n");
*/
}
/* GET_SWITCHES */
/*------------------------*/
get_switches()
/*------------------------*/
{ register char *swc; register int *val; char *index();
swc = CMD_BUF;
/* scan command line for slashes, and determine the switch */
while( swc = index( swc, '/' ) ){
switch( toupper(*++swc) ){
case 'B': /* set internal buffer size */
/* for reading the files */
val = &num_buf;
break;
case 'C': /* set number of comparisons */
/* defining a difference area */
val = &num_cmp;
break;
case 'D': /* set number of lines to dis- */
/* play prior to difference area */
val = &num_disp;
break;
case 'W':
white_space = TRUE; /* Ignore multiple white spaces */
break;
case 'H':
help();
break;
default:
err_exit("\nUnknown switch specified");
}
/* get value for the switch, and check minimums */
if( val != NULL )
sscanf( ++swc, "%d", val );
if( num_buf < MIN_BUF )
num_buf = MIN_BUF;
if( num_cmp < NUM_CMP )
num_cmp = NUM_CMP;
if( num_disp < MIN_DISP )
num_disp = MIN_DISP;
}
}
/* OPEN_FILES, ASSIGN_BUFFERS */
/*---------------*/
open_files()
/*---------------*/
{ register int i;
if( argc < 3 ) /* if no files, show help message */
help();
/* open the files */
for( i = 0; i < 2; ++i ){
if( ! (file[ i ] = fopen( argv[i+1], "r" )) ){
printf( "\n%s", argv[i+1] );
err_exit( CANT_OPEN ); /* oh, s-s-sigh!! */
}
}
if( ! (file[ 3 ] = fopen("DELFILES.CMD", "w" )) ){
printf( "\n%s", "DELFILES.CMD");
err_exit( CANT_OPEN );
}
if( ! (file[ 4 ] = fopen("GETFILES.CMD", "w" )) ){
printf( "\n%s", "GETFILES.CMD");
err_exit( CANT_OPEN );
}
}
/*------------------------*/
assign_buffers()
/*------------------------*/
{ unsigned int i;
/*
divide available memory between "file1"
and "file2" in 128 byte chunks
*/
i = (coreleft() - 1000) / 2;
if( i > (num_buf <<= 7) )
i = num_buf;
(char *) lines[ 0 ] = alloc( i );
(char *) lines[ 1 ] = alloc( i );
if( (lines[ 0 ] == NULL)
|| (lines[ 1 ] == NULL)
|| (i < ( MIN_BUF << 7 ))
){
err_exit( "\nNot enough memory" );
}
/* initialize LINE pointers */
(char *) l_end[ 0 ] = (char *)(lines[ 0 ]) + i;
(char *) l_end[ 1 ] = (char *)(lines[ 1 ]) + i;
for( i = 0; i < 2; ++i ){
lines[i]->num_this
= lines[i]->num_prev
= 0;
lines[i]->line_num = 1;
c_inx[i]
= l_inx[i]
= lines[ i ];
l_inx[i]->line[0] = '\0';
}
}
/* ERR_EXIT, CHRPOS */
/*-----------------------------*/
err_exit( msg ) char *msg;
/*-----------------------------*/
{
printf( msg ); /* tell 'm off */
exit(0); /* and give up */
}
/*-------------------------------------------------*/
unsigned int chrpos(str, c) char *str; char c;
/*-------------------------------------------------*/
/* give position of char 'c' in string "str" */
/* return -1 if not found. Note: length of */
/* "str" is returned if 'c' is '\0'. */
{
register unsigned int i = 0;
do{
if( str[i] == c )
return(i);
}while( str[ i++ ] != '\0' );
return(-1);
}
/*---------------------*/
check_abort()
/*---------------------*/
{
if( (bdos( 6, 0xFF ) & 0xFF) == ('C' & 0x1F ) )
exit( 0 );
}
/*----------------------------------------------*/
cmp_line( s1, s2 ) register char *s1, *s2; /* Compare two lines */
/*----------------------------------------------*/
{ static int s1_char, s2_char;
if( strcmp( s1, s2 ) == 0 )
return TRUE;
if( ! white_space )
return FALSE;
s1 = p_non_white( s1 );
s2 = p_non_white( s2 );
while( ((s1_char = *s1) != '\0')
&& ((s2_char = *s2) != '\0')
){
if( (is_white( s1_char ))
&& (is_white( s2_char ))
){
s1 = p_non_white( s1 );
s2 = p_non_white( s2 );
}
else{
if( s1_char != s2_char )
return FALSE;
++s1;
++s2;
}
}
if( *p_non_white( s1 ) == *p_non_white( s2 ))
return TRUE;
return FALSE;
}
/*------------------------------*/
is_white( c ) char c;
/*------------------------------*/
{
switch( c ){
case ' ':
case '\t':
case '\f':
return TRUE;
}
return FALSE;
}
/*------------------------------------*/
char *p_non_white( cp ) register char *cp;
/*------------------------------------*/
{
while( is_white( *cp ) )
++cp;
return cp;
}
/*------------------------*/
help()
/*------------------------*/
{ register char **usage = USAGE;
while( *usage != NULL )
printf( "%s", *usage++ );
/* printf( CUR_DEFAULT
* , num_disp
* , num_cmp
* , num_buf
* , (white_space ? ON : OFF)
* );
*/
exit(0);
}