{ ========================================= program: CCAT | CCAT is a program which compares two | author: Richard F. Mack | MAST.LST output files from the MCAT | 3407A Courtleigh Dr. | and XCAT programs. The output of | Baltimore, MD 21207 | CCAT is a double-ended listing of the | 301-922-1176 | the files in each MAST.LST which are | date: 24 DEC 85 | not common to both. The output of | version: 2.6 | CCAT is displayed on the screen and | | is written either to the printer or | | or to a disk file. This version of | | CCAT is a complete rewrite of early | | versions and adds nice formatting to | | the output display. | ========================================= NOTES: If user wishes to rename CCATxx.COM, the source file must be recompiled - otherwise the overlay will not be found at run-time. A run-time error (F0) will be indicated. Arrays below are dimensioned for 62K of available memory. If memory overflow occurs, reduce the values of MaxCatSize and MaxNumberOfLines (just below) in a 10:1 ratio and recompile. CCAT must be run from the logged drive. (The program expects the to find the overlay on the logged drive during execution.) version 2.6 - correct identification of EMPTY filename } Program CompareCatalogs; {$U-,C-} Const NameLength = 12; NameWithDrive = 14; HeaderLength = 65; MaxCatSize = 3000; { This or less in reference list - FileOne. } MaxNumberOfLines = 300; TempOut1 = 'Temp1.$$$'; TempOut2 = 'Temp2.$$$'; Type FileName = string[NameLength]; FNameWithDrive = string[NameWithDrive]; Header = string[HeaderLength]; Sentence = string[60]; Var FirstCatSize,SecondCatSize,MismatchCount1,MismatchCount2: integer; OutFileOpen,FirstPass,Mismatch1,Mismatch2,Hardcopy: boolean; BakUpName,LineBuffer: FileName; ReferenceList,ExaminedList,OutFileName: FNameWithDrive; FileHeader1,FileHeader2: Header; FileOne,FileTwo,OutFile,TempOutFile1,TempOutFile2: text; procedure Help; type Paragraph = array[1..14] of Sentence; const Instruction: Paragraph = ('Usage:', '', 'Place CCAT on the logged drive.', '', 'Input MAST.LST files may be entered on the command line:', '', ' A>CCAT MAST.LST B:MAST.LST', '', 'If not entered on the command line, user is prompted', 'for data.', '', 'Output may be directed either to the printer or to disk.', 'Unless otherwise specified, differences between the', 'MAST.LST input files are written to ODDFILE.LST.'); var i: integer; begin writeln(^J); for i := 1 to 14 do writeln(^I,Instruction[i]); halt end; function Open(var fp:text; name: FNameWithDrive): boolean; begin Assign(fp,Name); {$I-} reset(fp); {$I+} If IOResult <> 0 then begin Open := False; close(fp); end else Open := True; end { Open }; procedure Abort(s: Sentence; f: FNameWithDrive); begin writeln(^J,'ABORT - ',s,f); halt; end; procedure OpenInputFiles; var Answer: char; procedure CapStr(LowCaseStr: FNameWithDrive; var UpCaseStr: FNameWithDrive); var i: integer; begin UpCaseStr := ''; for i := 1 to length(LowCaseStr) do begin UpCaseStr := UpCaseStr + UpCase(copy(LowCaseStr,i,1)); end; end {CapStr}; procedure WriteHeader; begin Writeln('CCAT Catalog Comparison Utility - Version 2.6 12/24/85',^J); end; begin {OpenInputFiles} OutFileName := ''; If ParamCount = 0 then begin WriteHeader; Write('Enter first filename: '); readln(ReferenceList); Write(^J,'Enter second filename: '); readln(ExaminedList); end else begin WriteHeader; ReferenceList := ParamStr(1); ExaminedList := ParamStr(2); if ParamCount <> 2 then begin if ParamStr(1) = '?' then Help else if UpCase(copy(ParamStr(1),1,1)) = 'H' then Help else begin writeln(^J,'Try again - ERROR in entering input filenames.'); halt end; end; end; writeln(^J,'Do you want hard copy instead of disk file? (Y/N)'); read(kbd,Answer); Hardcopy := (UpCase(Answer) = 'Y'); if not Hardcopy then begin Write(^J,'Enter output filename or : '); readln(OutFileName); end; if OutFileName = '' then OutFileName := 'ODDFILE.LST'; CapStr(ReferenceList,ReferenceList); CapStr(ExaminedList,ExaminedList); CapStr(OutFileName,OutFileName); if not Open(FileOne,ReferenceList) then Abort('File not found: ',ReferenceList); if not Open(FileTwo,ExaminedList) then Abort('File not found: ',ExaminedList); FirstPass := true; end {OpenInputFiles}; procedure ExchangeInputFiles; begin if not Open(FileOne,ExaminedList) then Abort('File not found: ',ExaminedList); if not Open(FileTwo,ReferenceList) then Abort('File not found: ',ReferenceList); FirstPass := false; end {ExchangeInputFiles}; function Exist(FileN: FNameWithDrive): boolean; var F: file; begin assign(F,FileN); {$I-} reset(F); {$I+} Exist := (IOResult = 0); end {Exist}; procedure BakUp; begin if Exist(OutFileName) then begin BakUpName:=copy(OutFileName,1,length(OutfileName)-3)+'BAK'; if Exist(BakUpName) then begin assign(OutFile,BakUpName); erase(OutFile) end; assign(OutFile,OutFileName); rename(OutFile,BakUpName) end; end {BakUp}; procedure OpenOutputFile; Begin Assign(OutFile,OutFileName); {$I-} Rewrite(OutFile); {$I+} OutFileOpen := (IOResult = 0); if not OutFileOpen then Abort('Can''t open ',OutFileName); end {OpenOutputFile}; procedure OpenTempFiles; var TempFileOpen: boolean; Begin Assign(TempOutFile1,TempOut1); {$I-} Rewrite(TempOutFile1); {$I+} TempFileOpen := (IOResult = 0); if not TempFileOpen then Abort('Can''t open temporary file: ',TempOut1); Assign(TempOutFile2,TempOut2); {$I-} Rewrite(TempOutFile2); {$I+} TempFileOpen := (IOResult = 0); if not TempFileOpen then Abort('Can''t open temporary file: ',TempOut2); end {OpenTempFile}; procedure ReopenTempFile(var TempOutFile: text; TempOut: FileName); var TempFileOpen: boolean; begin Assign(TempOutFile,TempOut); {$I-} Reset(TempOutFile); {$I+} TempFileOpen := (IOResult = 0); if not TempFileOpen then Abort('Can''t open temporary file: ',TempOut); end; {ReopenTempFile} overlay procedure ProcessFile; const BuffSize = 100; { bite of FileTwo taken at each disk access } type InputBuff = array[1..BuffSize] of FileName; Catalog = array[1..MaxCatSize] of FileName; var i,n,MismatchCounter,StartSearchPoint: integer; CompareBuffFull,Mismatch,Temp1Open,Temp2Open: boolean; OddOne,ProgramName: FileName; CompareBuff: InputBuff; RefFile: Catalog; procedure BinarySearch; var j,OffSet: integer; Match,NotOnList: boolean; procedure OutMismatchToDisk; var TempFile1Open,TempFile2Open: boolean; begin if FirstPass then begin FileHeader1 := 'The following files in ' + ExaminedList + ' do not appear in ' + ReferenceList; writeln(TempOutFile1,OddOne); end else begin FileHeader2 := 'The following files in ' + ReferenceList + ' do not appear in ' + ExaminedList; writeln(TempOutFile2,OddOne); end; end {OutMismatchToDisk}; begin {BinarySearch} j := StartSearchPoint; OffSet := j; Match := false; NotOnList := false; repeat if ProgramName = RefFile[j] then begin Match := true; end else if ProgramName < RefFile[j] then begin OffSet := OffSet div 2; if OffSet = 0 then NotOnList := true else j := j - OffSet; end else if ProgramName > RefFile[j] then begin if j + OffSet div 2 > FirstCatSize then begin repeat OffSet := OffSet div 2; until j + OffSet div 2 <= FirstCatSize end; OffSet := OffSet div 2; if OffSet = 0 then NotOnList := true else j := j + OffSet; end; until Match or NotOnList; If not Match then begin if ProgramName <> '' then {string empty? Not enough data in grab to completely fill buffer.} begin Mismatch := true; OddOne := ProgramName; OutMismatchToDisk; MismatchCounter := succ(MismatchCounter); if FirstPass then begin writeln(OddOne,' doesn''t appear in ',ReferenceList) end else begin writeln(OddOne,' doesn''t appear in ',ExaminedList); end; end; end; end { BinarySearch }; begin {Process File} MismatchCounter := 0; For i := 1 to MaxCatSize do RefFile[i] := ''; { initialize buffer } if FirstPass then begin OutFileOpen := false; Writeln(^J,'Reading ',ReferenceList,' . . . '); end else Writeln(^J,'Reading ',ExaminedList,' . . . '); i:=1; while not Eof(FileOne) do begin Readln(FileOne,LineBuffer); if copy(LineBuffer,9,1) = '.' then begin if copy(lineBuffer,10,3) <> 'FRE' then begin RefFile[i] := copy(LineBuffer,1,12); FirstCatSize := i; i := succ(i); end; end; end; if i = 1 then begin if FirstPass then writeln(^J,ReferenceList,' is an EMPTY file.') else writeln(^J,ExaminedList,' is an EMPTY file.'); close(TempOutFile1); erase(TempOutFile1); close(TempOutFile2); erase(TempOutFile2); halt end; close(FileOne); StartSearchPoint := 2; if StartSearchPoint < FirstCatSize then repeat StartSearchPoint := StartSearchPoint * 2 until StartSearchPoint >= FirstCatSize; StartSearchPoint := StartSearchPoint div 2; Mismatch := false; if FirstPass then Writeln(^J,'Reading ',ExaminedList,' . . . ',^J) else Writeln(^J,'Reading ',ReferenceList,' . . . ',^J); begin SecondCatSize := 0; repeat For i := 1 to BuffSize do CompareBuff[i] := ''; { initialize buffer } i := 1; CompareBuffFull := false; repeat readln(FileTwo,LineBuffer); if copy(LineBuffer,9,1) = '.' then begin if copy(lineBuffer,10,3) <> 'FRE' then begin CompareBuff[i] := copy(LineBuffer,1,12); if i >= BuffSize then CompareBuffFull := true; i:=succ(i); SecondCatSize := succ(SecondCatSize); end; end; until CompareBuffFull or Eof(FileTwo); { begin comparing the big reference array against chunks of the other list taken from disk } n := 1; while n <= BuffSize do begin ProgramName := CompareBuff[n]; BinarySearch; n := succ(n); end; until Eof(FileTwo); end; close(FileTwo); if not Mismatch then begin if FirstPass then begin Mismatch1 := false; writeln(^J,'Everything in the ',ExaminedList, ' file also appears in the ',ReferenceList,' file.'); end else begin Mismatch2 := false; writeln(^J,'Everything in the ',ReferenceList, ' file also appears in the ',ExaminedList,' file.'); end; end; if FirstPass then writeln(^J,'First comparison complete') else writeln(^J,'Second comparison complete'); if not Mismatch1 and not Mismatch2 and not FirstPass then begin writeln(^J,'Files in ' + ReferenceList + ' = ',SecondCatSize); writeln(^J,'Files in ' + ExaminedList + ' = ',FirstCatSize); end; if Mismatch then begin if FirstPass then begin Mismatch1 := true; MismatchCount1 := MismatchCounter end else begin Mismatch2 := true; MismatchCount2 := MismatchCounter; end; if not FirstPass then writeln(^J,'Formatting output . . .'); end; if FirstPass then close(TempOutFile1) else close(TempOutFile2); end {Process File}; overlay procedure FormatOutput; const NumberOfColumns = 5; type Page = array[1..MaxNumberOfLines] of array[1..NumberOfColumns] of FileName; var MinColumnLength: integer; LineBuffer: string[79]; NoMatch1,NoMatch2: Page; procedure ClrArray(var FileDisplay: Page; MismatchCount: integer); var i,j: integer; begin MinColumnLength := MismatchCount div NumberOfColumns; for i := 1 to NumberOfColumns do begin for j := 1 to MinColumnLength + 1 do FileDisplay[j,i] := ''; end; LineBuffer := ''; end; {ClrArray} procedure PrettyItUp(var FileDisplay: Page; var TFile: text; MismatchCount: integer); var i,j,Residue,AddOn: integer; begin MinColumnLength := MismatchCount div NumberOfColumns; Residue := MismatchCount - NumberOfColumns * MinColumnLength; for i := 1 to NumberOfColumns do begin AddOn := 0; if Residue > 0 then begin AddOn := 1; Residue := Residue - 1; end; for j := 1 to MinColumnLength + AddOn do begin readln(TFile,LineBuffer); FileDisplay[j,i] := LineBuffer; end; {j loop} end; {i loop} close(TFile); erase(TFile); end; {PrettyItUp} procedure WriteItOut(var FileDisplay: Page; FileHeader: Header; NumOfMismatches: integer); var i,j: integer; procedure Summary; var SummaryStringA,SummaryStringB, SummaryStringC,SummaryStringD: string[79]; begin SummaryStringA := 'Files in ' + ReferenceList + ' = '; SummaryStringB := 'Files in ' + ExaminedList + ' = '; SummaryStringC := 'Files in ' + ExaminedList + ' which are not found in ' + ReferenceList + ' = '; SummaryStringD := 'Files in ' + ReferenceList + ' which are not found in ' + ExaminedList + ' = '; writeln(^J,SummaryStringA,SecondCatSize); writeln(SummaryStringB,FirstCatSize); if FileHeader = FileHeader1 then writeln(SummaryStringC,NumOfMismatches,^J) else writeln(SummaryStringD,NumOfMismatches); if not Hardcopy then begin writeln(OutFile,^J,SummaryStringA,SecondCatSize); writeln(OutFile,SummaryStringB,FirstCatSize); if FileHeader = FileHeader1 then writeln(OutFile,SummaryStringC,NumOfMismatches,^J) else writeln(OutFile,SummaryStringD,NumOfMismatches); end else begin writeln(lst,^J,SummaryStringA,SecondCatSize); writeln(lst,SummaryStringB,FirstCatSize); if FileHeader = FileHeader1 then writeln(lst,SummaryStringC,NumOfMismatches,^J) else writeln(lst,SummaryStringD,NumOfMismatches); end; end; {Summary} begin {WriteItOut} writeln(^J,FileHeader,^J); if not Hardcopy then writeln(OutFile,^J,FileHeader,^J) else writeln(lst,^J,FileHeader,^J); for j := 1 to MinColumnLength +1 do begin write(FileDisplay[j,1]); if not Hardcopy then write(OutFile,FileDisplay[j,1]) else write(lst,FileDisplay[j,1]); for i := 2 to NumberOfColumns do begin write(FileDisplay[j,i]:16); if not Hardcopy then write(OutFile,FileDisplay[j,i]:16) else write(OutFile,FileDisplay[j,i]:16); end; writeln; if not Hardcopy then writeln(OutFile) else writeln(lst); end; Summary; end; {WriteItOut} begin {FormatOutput} if not Hardcopy then begin if Mismatch1 or Mismatch2 then begin BakUp; OpenOutputFile; end; end; if Mismatch1 then begin ReopenTempFile(TempOutFile1,TempOut1); ClrArray(NoMatch1,MismatchCount1); PrettyItUp(NoMatch1,TempOutFile1,MismatchCount1); WriteItOut(NoMatch1,FileHeader1,MismatchCount1); end; if Mismatch2 then begin ReopenTempFile(TempOutFile2,TempOut2); ClrArray(NoMatch2,MismatchCount2); PrettyItUp(NoMatch2,TempOutFile2,MismatchCount2); WriteItOut(NoMatch2,FileHeader2,MismatchCount2); end; if not Mismatch1 then begin close(TempOutFile1); erase(TempOutFile1); end; if not Mismatch2 then begin close(TempOutFile2); erase(TempOutFile2); end; if not Hardcopy then begin if Mismatch1 or Mismatch2 then writeln(^J,'Output File = ',OutFileName); end; if OutFileOpen then close(OutFile); end; {FormatOutput} BEGIN {main program} ClrScr; OpenInputFiles; OpenTempFiles; ProcessFile; ExchangeInputFiles; ProcessFile; FormatOutput; END.