Category : Files from Magazines
Archive   : DDJ8708.ZIP
Filename : KRANZLST.AUG

 
Output of file : KRANZLST.AUG contained in archive : DDJ8708.ZIP
/*------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Name: DIFF.C
-- Processor: VAX | MS-DOS
-- Class: C Program
-- Creation Date: 1/8/87
-- Revision:
-- Author: D. Krantz
--
-- Description: File compare and change-bar for text files.
--
--------------------------------------------------------------------------------
------------------------------------------------------------------------------*/

/* File Difference Utility */

#include
#include

#define OPT_FLAG '/' /* command line option switch recognizer */

#ifdef VAX11C
#define MAXLINE 16 /* maximum characters in input line */
#else
#define MAXLINE 85
#endif

#define FORMFEED 'L'-'@'

struct LINE { /* structure defining a line internally */
int linenum; /* what line on page */
int pagenum; /* what page line is from */
struct LINE *link; /* linked list pointer */
char text[ MAXLINE ]; /* text of line */
char dup[ MAXLINE ]; /* uppercase copy of line text */
};

typedef struct LINE *line_ptr;

typedef char *char_ptr;

typedef FILE *FILE_PTR;

struct LINE root[ 3 ]; /* root of internal linked lists */

FILE_PTR msg; /* differences summary file pointer */

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; /* how many command line errors */
char xx1[ 132 ], xx2[ 132 ]; /* space to retain file names */
int files = 0; /* how many files specified on command line */
char_ptr infile_name[ 3 ] = { NULL, xx1, xx2 };
char outfile_name[ 132 ]; /* changebarred output filename */
FILE_PTR infile[ 3 ]; /* input file pointers */
FILE *outfile; /* changebarred output file pointer */
static line_ptr at[ 3 ] = { NULL, &(root[ 1 ]), &(root[ 2 ]) };

int debug = 0; /* trace switch */
int trace_enabled = 0; /* keyboard tracing switch */
int bar_col = 78; /* column where change bar is to appear */
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, is upper/lower case significant? */
int re_sync = 5; /* lines that must match for resynchronization */
int output = 0; /* boolean, is change-barred output file on? */
int blanks = 0; /* boolean, are blank lines significant? */
int lookahead = 200; /* how many lines to look ahead before giving up */
int skip1 = 0; /* how many pages of first file to skip */
int skip2 = 0; /* how many pages of second file to skip */

#if 0 /* tracing and other debug functions turned off */

#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

/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
main( argc, argv )
int argc;
char *argv[];
{
int i;
trace( "main" );
if( argc == 1 )
help();
msg = stdout;
for( i = 1; i < argc; i++ )
strip_opt( argv[ i ] );
if( files < 2 )
{
printf( "\nError: Must specify two files" );
exit( 2 );
}
open_files();
if( command_errors )
exit( 2 );
page_skip();
diff();
ret;
}

/*------------------------------------------------------------------------------
DONT_LOOK - Tells us whether or not this line should be considered for
comparison or is a filler (e.g. header, blank) line.
------------------------------------------------------------------------------*/
dont_look( line )
line_ptr line;
{
int i;
trace( "dont_look" );
if( line == NULL )
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->text[ i ] )
{
case '\0':
case '\n':
ret_val( 1 );
case '\t':
case ' ':
break;
default:
ret_val( 0 );
}
}
ret_val( 0 );
}

/*------------------------------------------------------------------------------
EQUAL - tells us if the pointers 'a' and 'b' point to line buffers containing
equivalent text or not.
------------------------------------------------------------------------------*/
equal( a, b )
line_ptr a, b;
{
trace( "equal" );
if( (a == NULL) || (b == NULL) )
ret_val( 0 );
if( up_case )
ret_val( !strcmp( a->dup, b->dup ) )
else
ret_val( !strcmp( a->text, b->text ) )
}

/*------------------------------------------------------------------------------
POSITION - moves the input pointer for file 'f' such that the next line to
be read will be 'where'.
------------------------------------------------------------------------------*/
position( f, where )
int f;
line_ptr where;
{
trace( "position" );
at[ f ] = &root[ f ];
while( at[ f ]->link != where )
at[ f ] = at[ f ]->link;
ret;
}

/*------------------------------------------------------------------------------
FIX - fixes the end-of-line sequence on a VAX to be just a newline instead of
a carriage-return/newline.
------------------------------------------------------------------------------*/
char *fix( str )
char *str;
{
char *strsave;

trace( "fix" );
strsave = str;
if( str == NULL )
ret_val( NULL )
#ifdef VAX11C
while( *str != '\0' )
{
if( match( str, "\r\n" ) )
{
*str = '\n';
*(str + 1) = '\0';
}
str++;
}
#endif
ret_val( strsave );
}

/*------------------------------------------------------------------------------
INDEX - returns a pointer to the first occurance of 'c' in the string pointed
to by 'str', or NULL if 'str' does not contain 'c'.
------------------------------------------------------------------------------*/
char *index( str, c )
char *str, c;
{
trace( "index" );
while( (*str != c) && *(str++) );
if( *str == c )
ret_val( str )
ret_val( NULL );
}

/*------------------------------------------------------------------------------
NEXT_LINE - allocates, links, and returns the next line from file 'f' if no
lines are buffered, otherwise returns the next buffered line from file 'f'
and updates the link pointer to the next buffered line.
------------------------------------------------------------------------------*/
line_ptr next_line( f )
int f;
{
char *malloc();
line_ptr temp, place_hold;

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( "\nOut of Memory" );
exit( 2 );
}
place_hold = at[ f ];
at[ f ] = at[ f ]->link;
at[ f ]->link = NULL;
if( fix( fgets( at[ f ]->text, MAXLINE, infile[ f ] ) ) == NULL)
{
free( at[ f ] );
at[ f ] = place_hold;
at[ f ]->link = NULL;
ret_val( NULL )
}
#ifdef EMBEDDED_FORMFEEDS
if( (index( at[ f ]->text, FORMFEED ) != NULL) ||
(line_count[ f ] > page_len ) )
#else
if( ( *(at[ f ]->text) == FORMFEED) ||
(line_count[ f ] > page_len ) )
#endif
{
page_count[ f ]++;
line_count[ f ] = 1;
}
at[ f ]->linenum = line_count[ f ]++;
at[ f ]->pagenum = page_count[ f ];
if( up_case )
{
strcpy( at[ f ]->dup, at[ f ]->text );
upper( at[ f ]->dup );
}
ret_val( at[ f ] );
}
}

/*------------------------------------------------------------------------------
DISCARD - deallocates all buffered lines from the root up to and including
'to' for file 'f'.
------------------------------------------------------------------------------*/
discard( f, to )
int f;
line_ptr to;
{
line_ptr temp;

trace( "discard" );
for(;;)
{
if( root[ f ].link == NULL )
break;
temp = root[ f ].link;
root[ f ].link = root[ f ].link->link;
free( temp );
if( temp == to )
break;
}
at[ f ] = &root[ f ];
ret;
}

/*------------------------------------------------------------------------------
VFPUTS - for VAX, un-fixes newline at end of line to be carriage-return/newline.
------------------------------------------------------------------------------*/
vfputs( str, file )
char *str;
FILE *file;
{
int i;
trace( "vfputs" );
#ifdef VAX11C
for( i = 0; i < MAXLINE; i++ )
{
if( str[ i ] == '\n' )
{
strcpy( str + i, "\r\n" );
break;
}
}
fputs( str, file );
#else
fputs( str, file );
#endif
ret;
}

/*------------------------------------------------------------------------------
PUT - If change-barred output file is turned on, prints all lines from the
root of file 1 up to and including 'line'. This is called only if a match
exists for each significant line in file 2.
------------------------------------------------------------------------------*/
put( line )
line_ptr line;
{
line_ptr temp;

trace( "put" );
if( output )
for( temp = root[ 1 ].link; ; )
{
if( temp == NULL )
ret
vfputs( temp->text, outfile );
if( temp == line )
ret
temp = temp->link;
}
ret;
}

/*------------------------------------------------------------------------------
CHANGE_BAR - inserts a change-bar into the text pointed to by
'str' and returns a pointer to 'str'.
------------------------------------------------------------------------------*/
char *change_bar( str )
char *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 );
}

/*------------------------------------------------------------------------------
ADDED - 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.
------------------------------------------------------------------------------*/
added( line )
line_ptr line;
{
line_ptr temp;

trace( "added" );
for( temp = root[ 1 ].link; ; )
{
if( temp == NULL )
ret
if( !dont_look( temp ) )
fprintf( msg, "+%d:%d -> %s", temp->pagenum,
temp->linenum, temp->text );
if( output )
if( dont_look( temp ) )
vfputs( temp->text, outfile );
else
vfputs( change_bar( temp->text ), outfile );
if( temp == line )
ret
temp = temp->link;
}
}

/*------------------------------------------------------------------------------
DELETED - outputs a change summary for all lines in file 2 from the root up to
and including 'line'.
------------------------------------------------------------------------------*/
deleted( line )
line_ptr line;
{
line_ptr temp;

trace( "deleted" );
for( temp = root[ 2 ].link; ; )
{
if( temp == NULL )
ret
if( !dont_look( temp ) )
fprintf( msg, "-%d:%d -> %s", temp->pagenum,
temp->linenum, temp->text );
if( temp == line )
ret
temp = temp->link;
}
ret;
}

/*------------------------------------------------------------------------------
RESYNC - 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 all lines printed by this function.
------------------------------------------------------------------------------*/
resync( first, second )
line_ptr first, second;
{
line_ptr file1_start, file2_start, last_bad1, last_bad2, t1, t2;
int i, j ,k, moved1, moved2;

trace( "resync" );

moved1 = 0;
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;
file2_start = second;

position( 2, second );
for( j = 0; j < lookahead ; j++ )
{
while( dont_look( file2_start = next_line( 2 ) ) );
if( file2_start == NULL ) goto eof2;

t1 = file1_start;
t2 = 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 ) goto synced;

last_bad2 = file2_start;
position( 2, file2_start );
while( dont_look( file2_start = next_line( 2 ) ) );
moved2 ++;
}
eof2:
last_bad1 = file1_start;
position( 1, file1_start );
while( dont_look( file1_start = next_line( 1 ) ) );
moved1++;
}
printf( "\n*** ERROR - lost sync in file %s at page %d line %d",
infile_name[ 1 ], first->pagenum, first->linenum );
fclose( outfile );
exit( 2 );
no_sy:
position( 1, first );
while( (first = next_line( 1 )) != NULL )
{
added( first );
discard( 1, first );
}
ret;
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 );
fprintf( msg, "\n" );
ret;
}

/*------------------------------------------------------------------------------
DIFF - 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.
------------------------------------------------------------------------------*/
diff()
{
line_ptr first, second;

trace( "diff" );
for( ;; )
{
while( dont_look( first = next_line( 1 ) ) );
if( first == NULL )
{
put( first );
ret;
}
while( dont_look( second = next_line( 2 ) ) );
if( equal( first, second ) )
{
put( first );
discard( 1, first );
discard( 2, second );
}
else
resync( first, second );
if( second == NULL )
ret
}
}

/*------------------------------------------------------------------------------
PAGE_SKIP - 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, etc.
------------------------------------------------------------------------------*/
page_skip()
{
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;
}

/*------------------------------------------------------------------------------
HELP - outputs usage information.
------------------------------------------------------------------------------*/
help()
{
printf( "\nDIFF" );
printf( "\nText File Differencer and Change Barrer" );
printf( "\n" );
printf( "\nFormat:" );
printf( "\nDIFF [option{option}] newfile oldfile [barfile]" );
printf( "\n" );
printf( "\n newfile = latest revision of text file" );
printf( "\n oldfile = baseline to compare against" );
printf( "\n barfile = output file if changebars are desired" );
printf( "\n" );
printf( "\nOptions:" );
#ifdef TRACER_FUNCTIONS
printf( "\n /TRACE Makes a mess of the display and runs real
slow" );
printf( "\n default = trace off" );
printf( "\n" );
#endif
printf( "\n /BAR_COL=n Column of output file in which change bar
will appear" );
printf( "\n default = 78" );
printf( "\n" );
printf( "\n /TOP_SKIP=n Lines at top of page to skip for running
heads & page nos." );
printf( "\n default = 0" );
printf( "\n" );
printf( "\n /BOT_SKIP=n Lines at botom of page to skip for running
foots and page nos." );
printf( "\n default = 0" );
printf( "\n" );
printf( "\n /PAGE_LEN=n Lines per page (embedded formfeeds over-
ride)" );
printf( "\n default = 66" );
printf( "\n" );
printf( "\n /UP_CASE Upper/Lower case is significant/is not
significant" );
printf( "\n /NOUP_CASE default" );
printf( "\n" );
printf( "\n /RE_SYNC=n Lines that must match before files are
considered synced" );
printf( "\n after differences are found - default = 5" );
printf( "\n" );
printf( "\n /OUTPUT=file File to redirect differences summary to. " );
printf( "\n default = SYS$OUTPUT or console." );
printf( "\n" );
printf( "\n /BLANKS Blank lines are considered significant" );
printf( "\n /NOBLANKS default" );
printf( "\n" );
printf( "\n /LOOKAHEAD=n Lines to look ahead in each file to resync
after difference" );
printf( "\n default = 200" );
printf( "\n" );
printf( "\n /SKIP1=n Pages in NEWFILE to skip before compare.
Also sets /SKIP2" );
printf( "\n default = 0" );
printf( "\n" );
printf( "\n /SKIP2=n Pages in OLDFILE to skip before compare.
Must be after /SKIP1" );
printf( "\n default = 0" );
printf( "\n" );
}

/*------------------------------------------------------------------------------
OPEN_FILES - opens the input and output files.
------------------------------------------------------------------------------*/
open_files()
{
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;
}

/*------------------------------------------------------------------------------
REDIRECT - performs output redirection under VAX 11 VMS.
------------------------------------------------------------------------------*/
redirect( str )
char *str;
{
char filename[ 132 ], *ptr, *dest;

trace( "redirect" );
dest = filename;
if( (ptr = index( str, '=' ) + 1) == (char *)(NULL + 1) )
{
printf( "\nERROR in option %s", str );
command_errors++;
}
while( (*ptr != OPT_FLAG) && ((*(dest++) = *(ptr++)) != '\0') );
*dest = '\0';
if( (msg = fopen( filename, "w" )) == NULL )
{
printf( "\nERROR creating %s", filename );
command_errors++;
}
ret;
}

/*------------------------------------------------------------------------------
STRIP_OPT - processes each command line option.
------------------------------------------------------------------------------*/
strip_opt( str )
char *str;
{
trace( "strip_opt" );
upper( str );
if( str[ 0 ] == OPT_FLAG )
{
if( match( str + 1, "BAR_COL" ) )
bar_col = num( str );
else if( match( str + 1, "TOP_SKIP" ) )
top_skip = num( str );
else if( match( str + 1, "BOT_SKIP" ) )
bot_skip = num( str );
else if( match( str + 1, "PAGE_LEN" ) )
page_len = num( str );
else if( match( str + 1, "UP_CASE" ) )
up_case = 1;
else if( match( str + 1, "NOUP_CASE" ) )
up_case = 0;
else if( match( str + 1, "RE_SYNC" ) )
re_sync = num( str );
else if( match( str + 1, "BLANKS" ) )
blanks = 1;
else if( match( str + 1, "NOBLANKS" ) )
blanks = 0;
else if( match( str + 1, "LOOKAHEAD" ) )
lookahead = num( str );
else if( match( str + 1, "SKIP1" ) )
skip1 = skip2 = num( str );
else if( match( str + 1, "SKIP2" ) )
skip2 = num( str );
#ifdef TRACER_FUNCTIONS
else if( match( str + 1, "TRACE" ) )
trace_enabled = debug = 1;
#endif
else if( match( str + 1, "OUTPUT" ) )
redirect( str );
else
{
printf( "\nUnrecognized Option: %s", str );
command_errors++;
}
}
else
{
switch( files )
{
case 0:
strcpy( infile_name[ 1 ], str );
break;
case 1:
strcpy( infile_name[ 2 ], str );
break;
case 2:
strcpy( outfile_name, str );
output = 1;
break;
default:
printf( "\nError: Too many files at %s", str );
command_errors++;
break;
}
files++;
}
if( index( str + 1, OPT_FLAG ) != NULL )
strip_opt( index( str + 1, OPT_FLAG ) );
ret;
}

/*------------------------------------------------------------------------------
UPPER - converts the string 'str' to upper case.
------------------------------------------------------------------------------*/
upper( str )
char *str;
{
trace( "upper" );
for( ; ; )
{
if( *str == '\0' )
ret
*str = toupper( *str );
str++;
}
}

/*------------------------------------------------------------------------------
MATCH - looks for a match of 'str' with the first (strlen( str) ) characters
of 'pattern'. Returns 0 for no match, nonzero on match.
------------------------------------------------------------------------------*/
int match( str, pattern )
char *str, *pattern;
{
trace( "match" );
for( ; ; )
{
if( *str != *pattern )
ret_val( 0 )
str++;
pattern++;
if( *pattern == '\0' )
ret_val( 1 )
if( *str == '\0' )
ret_val( 1 )
if( *str == '=' )
ret_val( 1 )
}
}

/*------------------------------------------------------------------------------
NUM - returns the integer associated with a command line option. An equal
sign must appear in the option.
------------------------------------------------------------------------------*/
int num( str )
char *str;
{
trace( "num" );
if( index( str, '=' ) == NULL )
ret_val( 0 )
else
ret_val( atoi( index( str, '=' ) + 1 ) )
}

#ifdef TRACER_FUNCTIONS

char_ptr names[ 20 ];
int stack = 0;

callstack( str )
char *str;
{
int i;
char c;

names[ stack++ ] = str;
if( debug )
{
for( i = 0; i < stack; i++ )
printf( " " );
printf( "Entering %s\n", str );
}
#ifndef VAX11C
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" );
break;
default:
break;
}
}
#endif
}

callpop()
{
int i;
if( debug )
{
for( i = 0; i < stack; i++ )
printf( " " );
printf( "Exiting %s\n", names[ stack ] );
}
stack--;
}

#endif


  3 Responses to “Category : Files from Magazines
Archive   : DDJ8708.ZIP
Filename : KRANZLST.AUG

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/