Category : C Source Code
Archive   : VERCTL.ZIP
Filename : COMPARE.C

 
Output of file : COMPARE.C contained in archive : VERCTL.ZIP
/*
COMPARE.C
Copyright (C) Seven Valleys Software 1985,1988
Written for Seven Valleys Software by Cheyenne Wills &
Released For Public Distribution
All Rights Reserved

Permission is granted to freely distribute this code, but not for
profit, provided that this notice and the following disclaimer are
included in their entirety and without modifications of any sort. This
work may not be sold, or modified and sold, or included in any other
work to be sold, (except for a nominal media charge), without the
written permission of the author.

Permission is granted to modify the source code and distribute it in
modified form PROVIDED that the authors of any modifications identify
themselves with name and address following this header and that all such
modifications are clearly indicated as to location and purpose, with
descriptive comments that clearly indicate modified lines.

The author would appreciate hearing of any modifications that may be
made, but makes no guarantees that such modifications will be
distributed with future releases of this program.

Author's address:

Cheyenne C. Wills
12 West Locust St.
Mechanicsburg, Pa. 17055
(717) 697-5198

Written for
Seven Valley's Software
P.O. Box 99
Glen Rock, Pa 17327

Disclaimer:

No guarantees or warranties of any kind: This code is distributed
"AS IS" without any warranty of any kind, either expressed or implied,
including, but not limited to the implied warranties of merchantability
and fitness for a particular purpose. You are soley responsible for the
selection of the program to achieve your intended results and for the
results actually obtained. Should the program prove defective, you (and
not the author) assume the entire cost of all necessary servicing,
repair, or correction.

Neither the author nor anyone else who has been involved in the
creation, production or delivery of this program shall be liable for any
direct, indirect, consequential or incidental damages arising out of the
use or inability to use this program.

History:
Version Date Author Reason
------- -------- ------ ---------------------------------------------
2.0 08/01/84 CCW Written for Seven Valleys Software
2.1 08/15/85 CCW Added -i option and online doc
2.2 02/05/86 CCW Added -t and -w options
2.3 01/21/88 CCW OS/2 Support
2.4 11/21/88 CCW Make more portable (ANSI)
*/

char *VERSION = "COMPARE V2.4\n";
char *COPYR = "Copyright (C) Seven Valleys Software 1985,1988\n";

/*

COMPARE [options]

Where:

and are the two files to be compared

[options] are:

-l [] Generate output to file
defaults to COMPARE.LST
-w Ignore white space between 'words'
-t Ignore case
-p Generate output to the printer
-mn Resync on n lines (default is 2)
-cx,y Only compare cols x thru y

------------ following for update deck generation only ------------
-u [] Generate update deck to make file1 into file2
defaults to the ."UPT"
-sx,y Generate internal sequence numbers starting with x
and increment by y. Default if -s is omitted is 1,1
if -s is specified with out x and y then x=10000
y defaults to x
-x File1 already contains sequence numbers
------------ following for aide with editor shells only -----------
-i Use a sequence file (generated from UPDATE command)
name is ."SEQ"
will be deleted
*/

#include
#include
#include
#include
#include
#include "compare.h"

#define MAXLEN 256

int MINMATCH = 2;

struct { /* Temp */
long len;
char text[512];
} templine;

struct fanchor a,b;

FILE *outlist, *in0, *in1, *seqf;
FILE *console;
#define IOBUFSZ 4096
char iobuf0[IOBUFSZ];
char iobuf1[IOBUFSZ];

char updtname[64]; /* Update deck name */
char seqname[64]; /* Name of sequence file */
char *files[3]; /* Pointers to the names of the files */

char Match, Eof, Different, Edit, Print, ToAFile, XSeqf, Iwhite, Icase;

long seqstrt = 1; /* Sequencing start */
long seqincr = 1; /* Sequencing increment */
long seqcur = 0; /* Current sequence number */
long lastmseq = 0; /* Last matched sequence number */

int colstart = 1; /* Column starting position for compares */
int colend = MAXLEN+1; /* Column ending position for compares */

char Seqtype = 0; /* Type of sequencing */
#define GenSeq 0 /* Generate the sequence numbers (use 10000 10000) */
#define FileSeq 1 /* Seq numbers are already in the file (first 9 pos) */
#define UserSeq 2 /* Use sequence start and increment specified by user */
#define SeqFile 3

#define LINESPERPAGE 60
int curline = LINESPERPAGE+1;

void main(int argc,char *argv[])
{
char i, *cp;
int fi;

console=stdout;

/* Handle the quiet option */
if(strcmp(argv[argc-1],"-q")==0) {
console=fopen("NUL","w");
argc--;
}
else {
fputs(VERSION,stderr); /* Put out our header for version */
fputs(COPYR,stderr); /* Put out our header for version */
fflush(stderr);
}
/* We need at least two files */
if(argc<3) { /* Tell about the error */
fputs("\nMissing filename(s).\n",stderr);
cmndformat();
exit(12);
}


fi=0;
if(*argv[1]!='-') files[fi++]=argv[1];
if(*argv[2]!='-') files[fi++]=argv[2];

for(i=3;i cp=argv[i];
if(*cp != '-') {
fprintf(stderr,"\nInvalid argument %s",cp);
cmndformat();
exit(12);
}
cp++;
switch(tolower(*cp)) {
case 't':
Icase++;
break;
case 'w':
Iwhite++;
break;
case 'i':
Seqtype=SeqFile;
XSeqf++;
break;
case 'p': /* handle going to the printer */
if(fi<3) files[fi++]="PRN:";
Print++;
break;
case 'l': /* use an output file */
cp=argv[i+1];
if(i+1 files[fi++]=cp;
i++;
}
else
if(i+1==argc || *cp=='-'&& fi<3)
files[fi++]="COMPARE.LST";
break;
case 'u':
cp=argv[i+1];
if(i+1 files[fi++]=cp;
i++;
}
Edit++;
break;
case 's':
cp++;
Seqtype=UserSeq;
if(isdigit(*cp)) { /* Handle a number */
seqstrt = atol(cp);
cp += strspn(cp,"0123456789");
if(*cp==',') {
cp++;
seqincr = atol(cp);
}
else seqincr=seqstrt;
}
else seqstrt=seqincr=10000;
seqcur=seqstrt-seqincr;
break;
case 'x':
cp++;
Seqtype=FileSeq;
seqincr=10000;
break;
case 'c':
cp++;
if( isdigit(*cp) ) { /* Handle a number */
colstart = atoi(cp);
cp += strspn(cp, "0123456789");
if(*cp==',') {
cp++;
colend = atoi(cp);
}
}
else {
fputs("\nMissing starting and ending column positions.\n",stderr);
cmndformat();
exit(12);
}
colend=colend-colstart+1;
break;
case 'm':
cp++;
if( isdigit(*cp) ) { /* Handle a number */
MINMATCH = atoi(cp);
cp += strspn(cp, "0123456789");
}
else {
fputs("\nInvalid Match value.\n",stderr);
cmndformat();
exit(12);
}
break;
default:
break;
}
}

i=fi;
/* We need at least two files */
if(i<2) { /* Tell about the error */
fputs("\nMissing filename(s).\n",stderr);
cmndformat();
exit(12);
}
/* Now check the options specified */
if( Print && Edit ) { /* Too many options specified */
fputs("\nConflicting options -u and -p\n",stderr);
cmndformat();
exit(12);
}
if( Print && i>3 ) { /* Print and out file are conflicting */
fputs("\nConflicting options -p and output file\n",stderr);
cmndformat();
exit(12);
}

if( (in0=fopen(files[0],"r"))==NULL) { /* Error getting to file1 */
fprintf(stderr,"\nUnable to open file1 [%s]\n",files[0]);
exit(12);
}
if( (in1=fopen(files[1],"r"))==NULL) { /* Error getting to file2 */
fprintf(stderr,"\nUnable to open file2 [%s]\n",files[1]);
exit(12);
}

newext(updtname,files[0],"upt"); /* Generate the alt name now */
newext(seqname,files[0],"seq"); /* Generate the seq name now */

if(i==2) files[2]="CON";
if(i==3) ToAFile=1;
if(Edit&&i==2) {
files[2]=updtname;
fprintf(console,"\nCreating update file [%s]\n",updtname);
}
if(Print) files[2]="PRN";

if( (outlist=fopen(files[2],"w"))==NULL) { /* Error opening file */
fprintf(stderr,"\nUnable to create output file [%s]\n",files[2]);
exit(12);
}
if(XSeqf && (seqf=fopen(seqname,"rb"))==NULL) {
/* Error opening file */
fprintf(stderr,"\nUnable to read sequence file [%s]\n",seqname);
exit(12);
}
/* Beef up performance some */

setvbuf(in0,iobuf0,_IOFBF,IOBUFSZ);
setvbuf(in1,iobuf1,_IOFBF,IOBUFSZ);

initialize();

if(a.eof) fprintf(stderr,"File [%s] is empty.\n",argv[1]);
if(b.eof) fprintf(stderr,"File [%s] is empty.\n",argv[2]);
if(!Eof) {
Different=0;
compf();
if(!Different) fputs("The two files are identical.\n",console);
}
fclose(in0);
fclose(in1);
if(XSeqf) {
fclose(seqf); /* Close the sequence file */
unlink(seqname); /* and get rid of it */
}
fflush(outlist);
fclose(outlist);
if(Different) exit(4); /* Indicate that things are different */
exit(0);
}
void compf()
{
Match=1; /* I.E. Beginnings of files match */
for(;;) {
if(Match) fnoteq();
else {
Different=1;
findeq();
}
if(Eof&&Match) break;
}
}
endfanchor(x)
struct fanchor *x;
{
return( (x->curr==NULL)&&x->eof );
}
void mark(x) /* Causes beginning of fanchor to be positioned before current */
/* fanchor curr. buffers get reclaimed, line counters reset */
/* etc. */
struct fanchor *x;
{
struct line *p;

if(x->head!=NULL) {
while(x->head!=x->curr) { /* Reclaim buffers */
p=x->head->next;

free(x->head->text);
free(x->head);
x->head=p;
}
x->hline=x->cline;
if(x->curr==NULL) {
x->tail=NULL;
x->tline=x->cline;
}
}
}
void movecurr(struct fanchor *x,FILE *filex) /* Filex is the input file associated with fanchor x */
{ /* eof is set of eof is encountered on either fanchor */
if(x->curr) {
if(x->curr==x->tail) readline(x,filex);
x->curr=x->curr->next;
if(x->curr==NULL) Eof=1;
x->cline++;
}
else if(!x->eof) {
readline(x,filex);
x->curr=x->head;
x->cline=x->hline;
}
else Eof=1;
}
void readline(x,filex)
struct fanchor *x;
FILE *filex;
{
struct line *newline;
char *c;
long int l;
int i;
if(!x->eof) {
if( fgets(templine.text,MAXLEN,filex) ) {
i = strlen(templine.text); /* Ensure that there is */
if(templine.text[i] != '\n') { /* a newline at the end */
templine.text[i+1] = '\n';
templine.text[i+2] = '\0';
}
c=templine.text; /* Point to the start of the text */
if(Edit && filex==in0) {
switch(Seqtype) { /* Generate the sequence number */
case GenSeq: /* We are to generate the sequence */
case UserSeq:
seqcur+=seqincr; /* Increment */
break;
case FileSeq: /* The first item in the file is a number */
l=seqcur;
seqcur = atol(templine.text);
c += strspn(templine.text,"0123456789");
if(seqcur!=0) seqincr=seqcur-l;
if(*c!='\n') ++c; /* Handle a null line */
break;
case SeqFile:
l=seqcur;
fread(&seqcur,sizeof(seqcur),1,seqf);
if( feof(seqf) || ferror(seqf) ) {
fprintf(stderr,"\nPremature EOF on sequence file [%s]\n",seqname);
exit(12);
}
if(seqcur!=0) seqincr=seqcur-l;
default: break;
}
}
templine.len=strlen(c)+1; /* Get the len of the line */

newline=(struct line *)malloc(sizeof(struct line));
if(newline==NULL) { /* Out of memory */
fputs("\nInsuffecient Memory\n",stderr);
exit(12);
}
newline->text=malloc((size_t) templine.len);
if(newline->text==NULL) { /* Out of memory */
fputs("\nInsuffecient Memory\n",stderr);
exit(12);
}
strcpy(newline->text,c);
newline->seqnum=seqcur; /* Get the current sequence number */
newline->len=templine.len;
newline->next=NULL;
if(x->tail==NULL) {
x->head=newline;
x->tline=1;
x->hline=1;
}
else {
x->tail->next=newline;
x->tline++;
}
x->tail=newline;
}
x->eof = feof(filex);
}
}
void backtrack(struct fanchor *x, int *xlines)/* Causes the current position of fanchor X to become */
{ /* the new curr. XLINES is set to the number of lines */
/* from the new curr to the old curr inclusive */
*xlines=(int) (x->cline+1-x->hline);
x->curr=x->head;
x->cline=x->hline;
Eof=endfanchor(&a) || endfanchor(&b);
}
void compl(void) /* Compare the current lines of fanchors a and b */
/* returning match to signal their (non-) equivalence */
/* EOF on both files is considered a match, but eof on */
/* only one is a mismatch */
{
int cea,ceb; /* Ending columns for file a and file b */
int i;
char *ca,*cb;

if(a.curr==NULL || b.curr==NULL)
Match=(endfanchor(&a) && endfanchor(&b));
else {
if(Iwhite) {
Match = compx(a.curr,b.curr);
return;
}
cea = (int) min(a.curr->len,colend);
ceb = (int) min(b.curr->len,colend);
Match=(cea==ceb); /* Equal lens */
if(Match) { /* The lengths match.. so lets see if we can compare them */
if(cea<=colstart) Match=0;
else {
ca=a.curr->text;
cb=b.curr->text;
ca+=colstart-1;
cb+=colstart-1;
for(i=colstart;i if(Icase) {
if(!(Match=( tolower(*ca++)==tolower(*cb++))))
break;
}
else if(!(Match=(*ca++==*cb++)))
break;
}
}
}
}
}
int compx(l1,l2)
struct line *l1, *l2;
{
char sbuf1[MAXLEN+1], sbuf2[MAXLEN+1];
register char *c;
register int i;

for(i=0, c = l1->text; *c; c++)
if( !isspace(*c) ) sbuf1[i++] = (Icase) ? tolower(*c) : *c ;
sbuf1[i] = '\0';

for(i=0, c = l2->text; *c; c++)
if( !isspace(*c) ) sbuf2[i++] = (Icase) ? tolower(*c) : *c ;
sbuf2[i] = '\0';

if(strcmp(sbuf1,sbuf2) == 0) return 1;
return 0;
}
void fnoteq() /* Find a mismatch */
{
for(;;) {
movecurr(&a,in0);
movecurr(&b,in1);
mark(&a);
mark(&b);
compl();
if(Match && a.curr != NULL)
lastmseq=a.curr->seqnum; /* Remember the sequence number */
if(Eof || !Match) break;
}
}
void findeq(void)
{
char advanceb;
advanceb=1;
for(;;) {
advanceb = Eof ? endfanchor(&a):!advanceb;
if(advanceb) search(&a,in0,&b,in1);
else search(&b,in1,&a,in0);
if(Match) break;
}
report();
}
void search(x,filex,y,filey) /* Look ahead one line on fanchor y and search */
struct fanchor *x; /* for that line backtracking on fanchor x */
FILE *filex;
struct fanchor *y;
FILE *filey;
{
int count; /* Number of lines backtraced on x */

movecurr(y,filey);
backtrack(x,&count);
checkfullmatch(x,filex,y,filey);
count--;
while( count!=0 && !Match ) {
movecurr(x,filex);
count--;
checkfullmatch(x,filex,y,filey);
}
}
void checkfullmatch( /* From the current positions of x and y, which may */
x,filex,y,filey) /* match makesure that the next MINMATCH-1 lines */
struct fanchor *x; /* also match or set match = false */
struct fanchor *y;
FILE *filex;
FILE *filey;
{
int n;
struct line *savexcur, *saveycur;
int savexline, saveyline;

savexcur=x->curr;
saveycur=y->curr;
savexline=(int) x->cline;
saveyline=(int) y->cline;
compl();
for(n=MINMATCH-1; Match && n!=0;n--) {
movecurr(x,filex);
movecurr(y,filey);
compl();
}
x->curr=savexcur;
x->cline=savexline;
y->curr=saveycur;
y->cline=saveyline;
}
void report()
{
#define REPLACE 0
#define DELETE 1
#define INSERT 2
#define INSERTOF 3

int STATE;
int lineno;
struct line *p;
struct line *alast; /* Pointer to the last unmatched lines in file a */
struct line *blast; /* and file b */
long seq1;
long seq2;
long seq3;
long seq4;

if(!Edit) {
pagechk();
fputc('\n',outlist);
if(a.head!=a.curr)
for(lineno=(int) a.hline,p=a.head;p!=NULL && p!=a.curr;lineno++,p=p->next) {
pagechk();
fprintf(outlist," 1 %4d> %s",lineno,p->text);
}
if(b.head!=b.curr)
for(lineno=(int) b.hline,p=b.head;p!=NULL && p!=b.curr;lineno++,p=p->next) {
pagechk();
fprintf(outlist," 2 %4d> %s",lineno,p->text);
}
}
else { /* Handle a Update deck */

/* The following conditions are: */
/* a.head = first mismatched line in file 1 */
/* a.curr = first matched line in file 1 */
/* b.head = first mismatched line in file 2 */
/* b.curr = first matched line in file 2 */
alast=blast=NULL;
for(p=a.head;p!=a.curr && p!=NULL; p=p->next) alast=p;
for(p=b.head;p!=b.curr && p!=NULL; p=p->next) blast=p;

STATE=REPLACE;

if(alast==NULL) STATE=INSERT;
else if(blast==NULL) STATE=DELETE;

if(STATE==INSERT && lastmseq==0) STATE=INSERTOF;

switch(STATE) {

case REPLACE:
seq1=a.head->seqnum; /* Get the first sequence number */

fprintf(outlist,"./ R %ld",seq1);

if(a.head!=alast) {
seq2=alast->seqnum;
fprintf(outlist," %ld",seq2);
}
else seq2=seq1;
if(Seqtype!=GenSeq) {
seq4=b.cline-b.hline; /* Get the number of lines inserted */
seq2=(a.curr!=NULL)?a.curr->seqnum:seq1+(seq4*seqincr);
seq4=(seq2-seq1)/(seq4+1L);
seq3=seq1+seq4;
fprintf(outlist," $ %ld %ld",seq3,seq4);
}
fputc('\n',outlist);
for(p=b.head;p!=NULL && p!=b.curr;p=p->next)
fprintf(outlist,"%s",p->text);
break;

case INSERTOF:
seq1=a.curr->seqnum; /* Get the first sequence number */
fprintf(outlist,"./ R %ld",seq1);
seq2=seq1;
if(Seqtype!=GenSeq) {
seq4=b.cline-b.hline+1; /* Get the number of lines inserted */
p=a.curr->next;
seq2=(p!=NULL)?p->seqnum:seq1+(seq4*seqincr);
seq4=(p!=NULL)?(seq2-seq1)/(seq4+1L):seqincr;
seq3=seq1+seq4;
fprintf(outlist," $ %ld %ld",seq3,seq4);
}
fputc('\n',outlist);
for(p=b.head;(p!=NULL && p!=b.curr);p=p->next)
fprintf(outlist,"%s",p->text);
if(p==b.curr) fprintf(outlist,"%s",p->text);
break;

case INSERT:
fprintf(outlist,"./ I %ld",lastmseq);
if(Seqtype!=GenSeq) {
seq1=b.cline-b.hline; /* Number of lines inserted */
p=a.curr->next;
seq2=(p!=NULL)?a.curr->seqnum:seqincr;
seq2=(p!=NULL)?(seq2-lastmseq)/(seq1+1L):seqincr;

seq1=lastmseq+seq2;
fprintf(outlist," $ %ld %ld",seq1,seq2);
}
fputc('\n',outlist);
for(p=b.head;(p!=NULL && p!=b.curr);p=p->next)
fprintf(outlist,"%s",p->text);
break;
case DELETE:
fprintf(outlist,"./ D %ld",a.head->seqnum);
if(alast!=NULL) fprintf(outlist," %ld",alast->seqnum);
fputc('\n',outlist);
break;
default: break;
}
}
}
void initialize(void)
{
initfanchor(&a,in0);
initfanchor(&b,in1);
Eof=a.eof || b.eof;
templine.len=MAXLEN;
templine.text[0]='\0';
}
void initfanchor(x,filex)
struct fanchor *x;
FILE *filex;
{
x->curr=NULL;
x->head=NULL;
x->tail=NULL;
x->cline=0;
x->hline=0;
x->tline=0;
x->eof=feof(filex);
}
void cmndformat()
{
fputs("Command format:\n",console);
fputs("COMPARE [options]\n",console);
fputs("Where:\n",console);
fputs(" and are the two files to be compared\n",console);
fputs(" [options] are:\n",console);
fputs(" -l [] Generate output to file\n",console);
fputs(" defaults to COMPARE.LST\n",console);
fputs(" -t Ignore case\n",console);
fputs(" -w Ignore white space between 'words' in a line\n",console);
fputs(" -p Generate output to the printer\n",console);
fputs(" -mn Resync on n lines (default is 2)\n",console);
fputs(" -cx,y Only compare cols x thru y\n",console);
fputs(" ------------ following for update deck generation only ------------\n",console);
fputs(" -u [] Generate update deck to make file1 into file2\n",console);
fputs(" defaults to the .\"UPT\"\n",console);
fputs(" -sx,y Generate internal sequence numbers starting with x\n",console);
fputs(" and increment by y. Default if -s is omitted is 1,1\n",console);
fputs(" if -s is specified with out x and y then x=10000\n",console);
fputs(" y defaults to x\n",console);
fputs(" -x File1 already contains sequence numbers\n",console);
fputs("------------ following for aide with editor shells only -----------\n",console);
fputs(" -i Use a sequence file (generated from UPDATE command)\n",console);
fputs(" name is .\"SEQ\"\n",console);
fputs(" will be deleted\n",console);
}

void pagechk() /* Check to see if we are to do a page eject if we are printing */
{
if(ToAFile||Print) {
if(curline++ < LINESPERPAGE) return;
fputc('\f',outlist);
fputs(VERSION,outlist);
fprintf(outlist,"\n Comparing File 1:<%s> with File 2:<%s>\n\n",files[0],files[1]);
curline=5;
}
}

void newext(fbuff,filename,newext)
char *fbuff;
char *filename;
char *newext;
{
register char *in, *out;
in = filename;
out = fbuff;
while ( *in && *in != '.' )
*out++ = *in++;
*out++ = '.';
in = newext;
while ( *in )
*out++ = *in++;
return;
}


  3 Responses to “Category : C Source Code
Archive   : VERCTL.ZIP
Filename : COMPARE.C

  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/