PROGRAM CMPF
****
* cmpf - compare records line-by-line, side-by-side, noting discrepancies
LastUpdated... = "Rev: 17:03 07Jul1999 andrew 22 /roi/andrew/BP/CMPF"
***
* Copyright (C) 2000, Andrew McLaughlin.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
* or http://www.fsf.org/copyleft/gpl.html
*
*   Enjoy, Andrew McLaughlin - andrew@mclaughlin.orange.ca.us
*** 
* Abstract:
*
*    This program will attempt to generate a report where to files (typically
* programs) of common parentage are compared and printed side-by-side.  Where
* the text is alike the  lines are printed  on the same  line of the  report.
* Where they differ, the segments of text in a staggared format.
*
*    This produces a report where that  is  much  easier  to  read  than  the
* typical over-under format (as is used in the Unix diff command).  The  only
* drawback is this report only displays the first 40 characters of each  line
* (on the screen) and only half  of each line to  the reporting device.   (If
* the printer will handle 132 characters, you will see 60 chars of each line,
* 170 gives 80).
*
*    The theory utilized makes a serious assumption that the two files  being
* compared are of common  parentage.  For this  reason the design only  looks
* for three lines of  text  to  match  (in  either  direction)  in  order  to
* synchronize the output.
*
***
* Revision Log
* Project When.... Who....... Why............................................
*         AUG85    MCLAUGHLIN INITIAL CODING
* 001     02SEP86  MCLAUGHLIN Enhance to try for .IBAS
* 002     02-19-87 J DIGNAN   Print usage help if -Help specified
* 003     23FEB87  MCLAUGHLIN Alter usage display method.
* 004     02-17-88 J D        Put enhancement #001 into effect;
*                             remove hard-coded SETPTR to allow flexibility
* 005     04-01-88 J D        Remove printing of option info.
* 006     04Aug93  Andrew     Enhance to work under UniData.
* 007     12Oct93  Andrew     Added IGNORE option.
* 008     07Jul97  Andrew     Added code for landscape mode condensed font on an HPGL printer.
*      andrew   01-05-98 Enhance to ensure SETPTR command is resident.
*
****

$INCLUDE UPCASE.EQUATES

crt "[CMPF v1.4 ":field(LastUpdated...," ",1,3):" (c) 1985-1999, Andrew McLaughlin. All rights reserved.]"
EQU InfoBasic LIT "*"
EQU UniBasic LIT ""

PARM = convert(" ",@FM,trim(@SENTENCE))
del PARM<1>
InfoBasic CALL !BPIOCP
UniBasic  BPIOCP                                                                                                                 ;*[006]

DIM VOC.RECS(2), FILENAMES(2), RECORDNAMES(2)
PROMPT ''

GOSUB KEYWORDS                                                      ;* initialize
if ERROR then
   GOSUB USAGE
   STOP
END

CRT 'Starting compare of: ':FILENAMEA:' ':RECORDNAMEA:' <-> ':FILENAMEB:' ':RECORDNAMEB

* Open Files

OPEN.ERRORS = ''
OPEN FILENAMEA TO FILEA ELSE
   FILENAMEA = upcase(FILENAMEA)
   OPEN FILENAMEA TO FILEA ELSE
      OPEN.ERRORS := FILENAMEA:" "
   end
end
OPEN FILENAMEB TO FILEB ELSE
   FILENAMEB = upcase(FILENAMEB)
   OPEN FILENAMEB TO FILEB ELSE
      OPEN.ERRORS := FILENAMEB:" "
   end
end
if LEN(OPEN.ERRORS) then                                                                                                         ;*[004]
   PRINT 'Unable to open the following files:'
   PRINT OPEN.ERRORS
   STOP
END
READ.ERRORS = ""
read SOURCEA from FILEA, RECORDNAMEA else
   RECORDNAMEA = upcase(RECORDNAMEA)
   read SOURCEA from FILEA, RECORDNAMEA else
      READ.ERRORS := RECORDNAMEA:" "
   end
end
read SOURCEB from FILEB, RECORDNAMEB else
   RECORDNAMEB = upcase(RECORDNAMEB)
   read SOURCEB from FILEB, RECORDNAMEB else
      READ.ERRORS := RECORDNAMEB:" "
   end
end
if READ.ERRORS then
   CRT "Unable to read the following records:"
   CRT READ.ERRORS
   STOP
END
convert @VM:@SM to "}|" in SOURCEA
convert @VM:@SM to "}|" in SOURCEB
MORE.SOURCEA = SOURCEA NE ""
MORE.SOURCEB = SOURCEB NE ""

DISPLAYA    = ''                                                                                                                 ;*[001]
DISPLAYB    = ''                                                                                                                 ;*[001]
RECORDA    = ''                                                                                                                  ;*[001]
RECORDB    = ''                                                                                                                  ;*[001]
EOF.FILE.A = $FALSE
EOF.FILE.B = $FALSE
if DEBUG then                                                                                                                    ;*[004]
   PRINT '     RECORDS LOADED':CHAR(13):
END                                                                                                                              ;*[004]
PRINT 'Loading buffer.'

for I = 1 TO BUFFER.SIZE
   if DEBUG then                                                                                                                 ;*[004]
      PRINT I:CHAR(13):
   END                                                                                                                           ;*[004]
   REMOVE LINEA FROM SOURCEA SETTING MORE.SOURCEA
   EOF.FILE.A = not(MORE.SOURCEA)
   REMOVE LINEB FROM SOURCEB SETTING MORE.SOURCEB
   EOF.FILE.B = not(MORE.SOURCEB)
   GOSUB PROCESS.LINEA
   GOSUB PROCESS.LINEB
   if MOD(I,10) eq 0 then PRINT 'l':
   if EOF.FILE.A OR EOF.FILE.B then exit
NEXT I
if DEBUG then                                                                                                                    ;*[004]
   PRINT
END                                                                                                                              ;*[004]

INFINITY = LEN(RECORDA)
if LEN(RECORDB) GT INFINITY then
   INFINITY = LEN(RECORDB)
END

if not(PreserveWhiteSpace) then
   CONVERT ' ' TO '' IN RECORDA
   CONVERT ' ' TO '' IN RECORDB
end

WIDTH = 0
begin case
   case (DISPOSITION eq 'S')
      execute 'AUX.ON'
      execute 'TERM 132,66'
      WIDTH = 60
   case (DISPOSITION MATCH 'C':@VM:'')                              ;* CRT
      InfoBasic  execute "GET.TERM.TYPE HUSH"                                                                                    ;*[005]
      InfoBasic  SCREEN.WIDTH = @SYSTEM.RETURN.CODE<2>                                                                           ;*[005]
      UniBasic   SCREEN.WIDTH = @CRTWIDE                                                                                         ;*[006]
      if DEBUG then                                                                                                              ;*[005]
         PRINT "SCREEN WIDTH = ":SCREEN.WIDTH                                                                                    ;*[005]
      END                                                                                                                        ;*[005]
      WIDTH = (SCREEN.WIDTH-11)/2
   case (DISPOSITION eq 'L')
      RptWidth = 170                                                                                                             ;*[006]
      if FORM.NAME eq "HPIV_DP" then RptWidth = 80                                                                               ;*[006]
*[006]           execute 'SETPTR ,,,,,,BRIEF,DEST ':FORM.NAME
      execute "copy from NEWAC to VOC SETPTR" capturing Dummy                                                                 ;*[980105]
      execute "SETPTR ,":RptWidth:",64,,,,BRIEF,DEST ":FORM.NAME                                                                 ;*[006]
      PRINTER ON
      ESC$ = CHAR(27)                                                                                                            ;*[008]
      PRINT ESC$:"(0U":ESC$:"(s0p16.67h8.5v0s0b0T":                 ;* Line printer font ;*[008]
      PRINT ESC$:"&l1O":                                            ;* In landscape mode ;*[008]
      PRINT ESC$:"&l8D":                                            ;* 8 lines per inch ;*[008]
      PRINT ESC$:"&l2E":                                            ;* 2 line top margin ;*[008]
      PRINT ESC$:"&l65F":                                           ;* lines to print ;*[008]
      WIDTH = (RptWidth-11)/2
END CASE

WIDTH = INT(WIDTH)
FMT = 'L#':WIDTH
H = 'CMPF':SPACE(WIDTH - 8):TIMEDATE():FMT("PAGE  'P'",'R#':(WIDTH - 9))
H := "'L'":FMT(VOC.RECA<2>:' ':RECORDNAMEA,FMT):'      '
H := FMT(VOC.RECB<2>:' ':RECORDNAMEB,FMT):"'L'"
if DEBUG then                                                                                                                    ;*[004]
   PRINT 'HEADING:'
   PRINT H
   PRINT 'WIDTH: ':WIDTH
END                                                                                                                              ;*[004]
HEADING H

EOFA = $FALSE
EOFB = $FALSE

PTRA = 1
PTRB = 1
AS.NOT.IN.B = 0
BS.NOT.IN.A = 0
SKIPA = $FALSE
SKIPB = $FALSE
COUNT.DISC = 0

if DEBUG then                                                                                                                    ;*[005]
   if DISPOSITION MATCH 'S':@VM:'L' then
      PRINT 'OPTIONS IN EFFECT:'
      if DISPOSITION eq 'S' then
         PRINT 'ALL OUTPUT DIVERTED TO SLAVE PRINTER.'
      END
      ELSE
         PRINT 'All output diverted to lineprinter ':
         PRINT 'with form of ->':FORM.NAME:'<-'
      END
      if SHOW.DISC then
         PRINT 'Only discrepancies will be shown.'
      END ELSE
         PRINT 'Both discrepancies and non-discrepancies will be shown.'
      END
      PRINT 'Compare Resolution: ':Resolution
      PRINT 'I/O buffer size ':BUFFER.SIZE
      PAGE
   END
END                                                                                                                              ;*[005]

LOOP
   if DEBUG then                                                                                                                 ;*[005]
      PRINT "[DEBUG] EOFA=":EOFA:", EOFB=":EOFB                                                                                  ;*[005]
   END                                                                                                                           ;*[005]
until (EOFA OR EOFB)
   if (RECORDA<1> eq RECORDB<1>) then
      GOSUB FORMAT
   END ELSE
      COUNT.DISC += 1
      GOSUB FINDA.IN.B
      GOSUB FINDB.IN.A
      if DEBUG then                                                                                                              ;*[004]
         PRINT 'NEXTA.IN.B IS ':NEXTA.IN.B:' - NEXTB.IN.A IS ':NEXTB.IN.A
      END                                                                                                                        ;*[004]
      begin case
         case (NOTA.IN.B and NOTB.IN.A)
            GOSUB BLOWOUT
         case (NEXTB.IN.A LT NEXTA.IN.B)
            GOSUB EXPECTB
         case (NEXTA.IN.B LE NEXTB.IN.A)
            GOSUB EXPECTA
         case $TRUE; PRINT 'OTHERS'
      END CASE
   END
REPEAT

if DISPLAYA and DISPLAYB then GOSUB FlushAB
if DISPLAYA then GOSUB FlushA
if DISPLAYB then GOSUB FlushB
PRINT
PRINT "Comparison summary:"
PRINT "Number of discrepancies: ":COUNT.DISC
if AS.NOT.IN.B eq 0 then AS.NOT.IN.B = 'no'
if BS.NOT.IN.A eq 0 then BS.NOT.IN.A = 'no'
PRINT "There were ":AS.NOT.IN.B:" lines that exist in ":FILENAMES(1):"/":RECORDNAMES(1):" that do not exist in ":FILENAMES(2):"/":RECORDNAMES(2):"."
PRINT "There were ":BS.NOT.IN.A:" lines that exist in ":FILENAMES(2):"/":RECORDNAMES(2):" that do not exist in ":FILENAMES(1):"/":RECORDNAMES(1):"."
PRINTER OFF
PRINTER CLOSE
if DISPOSITION eq 'L' then PRINT
PRINT 'Done with: ':FILENAMEA:' ':RECORDNAMEA:' <-> ':FILENAMEB:' ':RECORDNAMEB
STOP

****
** FINDA.IN.B
****

FINDA.IN.B:
if DEBUG then                                                                                                                    ;*[004]
   PRINT 'IN FINDA.IN.B'
END                                                                                                                              ;*[004]
EOFA = LEN(RECORDA) eq 0
if EOFA then RETURN
FINDERA = RECORDA<1>
if DEBUG then                                                                                                                    ;*[004]
   PRINT 'FINDERA IS ->':FINDERA:'<-'
END                                                                                                                              ;*[004]
if (LEN(FINDERA) LE 188) then
   NOTA.IN.B = $FALSE
   LOCATE FINDERA IN RECORDB<1> SETTING POSB ELSE
      NOTA.IN.B = $TRUE
      POSB = INFINITY
   END
END ELSE

****
*      The following code simulates  the LOCATE statement for  when
* the target string is in  excess of  188 characters.   The  LOCATE
* statement tends to truncate otherwise.
****

   INDEX = INDEX(RECORDB,@FM:FINDERA:@FM,1)
   if DEBUG then                                                                                                                 ;*[004]
      PRINT 'INDEX IS ':INDEX
   END                                                                                                                           ;*[004]
   if (INDEX eq 0) then
      NOTA.IN.B = $TRUE
      POSB = INFINITY
   END ELSE
      NOTA.IN.B = $FALSE
      BLOCK = RECORDB[1,INDEX]
      POSB = COUNT(BLOCK,@FM) + (BLOCK NE '')
   END
END

if DEBUG then                                                                                                                    ;*[004]
   PRINT 'Found ':FINDERA:' at ':POSB
END                                                                                                                              ;*[004]
if not(NOTA.IN.B) and (Resolution gt 1) then
   RES.TEST.A = FIELD(RECORDA,@FM,2,RES.MINUS.1)
   RES.TEST.B = FIELD(RECORDB,@FM,POSB+1,RES.MINUS.1)
   if RES.TEST.A NE RES.TEST.B then
      NOTA.IN.B = $TRUE
      POSB = INFINITY
   END
   if DEBUG then                                                                                                                 ;*[004]
      if NOTA.IN.B then
         PRINT 'Resolution ':Resolution:' failed.'
      END ELSE
         PRINT 'Resolution ':Resolution:' succeeded.'
      END
   END                                                                                                                           ;*[004]
END
NEXTA.IN.B = POSB
RETURN


**-- FINDB.IN.A
FINDB.IN.A:
if DEBUG then                                                                                                                    ;*[004]
   PRINT 'IN FINDB.IN.A'
END                                                                                                                              ;*[004]
EOFB = LEN(RECORDB) eq 0
if EOFB then RETURN
FINDERB = RECORDB<1>
if DEBUG then                                                                                                                    ;*[004]
   PRINT 'FINDERB IS ->':FINDERB:'<-'
END                                                                                                                              ;*[004]
if (LEN(FINDERB) LE 188) then
   NOTB.IN.A = $FALSE
   LOCATE FINDERB IN RECORDA<1> SETTING POSA ELSE
      NOTB.IN.A = $TRUE
      POSA = INFINITY
   END
END ELSE
   INDEX = INDEX(RECORDA , @FM:FINDERB:@FM , 1)
   if DEBUG then                                                                                                                 ;*[004]
      PRINT 'INDEX IS ':INDEX
   END                                                                                                                           ;*[004]
   if (INDEX eq 0) then
      NOTB.IN.A = $TRUE
      POSA = INFINITY
   END ELSE
      NOTB.IN.A = $FALSE
      BLOCK = RECORDA[1,INDEX]
      POSA = COUNT(BLOCK,@FM) + (BLOCK NE '')
   END
END

if DEBUG then                                                                                                                    ;*[004]
   PRINT 'Found ':FINDERB:' at ':POSA
END                                                                                                                              ;*[004]
if not(NOTB.IN.A) and (Resolution GT 1) then
   RES.TEST.B = FIELD(RECORDB,@FM,2,RES.MINUS.1)
   RES.TEST.A = FIELD(RECORDA,@FM,POSA+1,RES.MINUS.1)
   if RES.TEST.A NE RES.TEST.B then
      NOTB.IN.A = $TRUE
      POSA = INFINITY
   END
   if DEBUG then                                                                                                                 ;*[004]
      if NOTB.IN.A then
         PRINT 'Resolution ':Resolution:' failed.'
      END ELSE
         PRINT 'Resolution ':Resolution:' succeeded.'
      END
   END                                                                                                                           ;*[004]
END
NEXTB.IN.A = POSA
RETURN


**-- BLOWOUT
BLOWOUT:
if DEBUG then                                                                                                                    ;*[004]
   PRINT 'IN BLOWOUT'
END                                                                                                                              ;*[004]
BUFFERA = RECORDA<1>
BUFFERB = RECORDB<1>
GOSUB DEL.RECORDA
GOSUB DEL.RECORDB
COUNTA = 1
COUNTB = 1
LOOP
   if DEBUG then                                                                                                                 ;*[004]
      PRINT 'PTRA IS ':PTRA:' - PTRB IS ':PTRB
   END                                                                                                                           ;*[004]
   GOSUB FINDA.IN.B
   GOSUB FINDB.IN.A
until not(NOTA.IN.B and NOTB.IN.A) OR EOFA OR EOFB
   COUNTA += 1
   BUFFERA<COUNTA> = RECORDA<1>
   GOSUB DEL.RECORDA
   COUNTB += 1
   BUFFERB<COUNTB> = RECORDB<1>
   GOSUB DEL.RECORDB
REPEAT
if EOFA OR EOFB then
   GOSUB FlushA
   GOSUB FlushB
   RETURN
END
begin case
   case not(NOTA.IN.B)
      COUNTB += NEXTA.IN.B - 1
   case not(NOTB.IN.A)
      COUNTA += NEXTB.IN.A - 1
END CASE
if DEBUG then                                                                                                                    ;*[004]
   PRINT 'COUNTA IS ':COUNTA:' - COUNTB IS ':COUNTB
END                                                                                                                              ;*[004]
RECORDA = BUFFERA:@FM:RECORDA
RECORDB = BUFFERB:@FM:RECORDB
SKIPA = $FALSE
SKIPB = $TRUE
for I = 1 TO COUNTA
   GOSUB FORMAT
NEXT I
SKIPA = $TRUE
SKIPB = $FALSE
for I = 1 TO COUNTB
   GOSUB FORMAT
NEXT I
SKIPA = $FALSE
SKIPB = $FALSE
RETURN


**-- EXPECTA
EXPECTA:
if DEBUG then                                                                                                                    ;*[004]
   PRINT 'IN EXPECTA'
   PRINT 'NEXTA.IN.B IS ':NEXTA.IN.B
END                                                                                                                              ;*[004]
SKIPA = $TRUE
LAST = NEXTA.IN.B - 1
for I = 1 TO LAST
   GOSUB FORMAT
NEXT I
SKIPA = $FALSE
RETURN
**-- EXPECTB
EXPECTB:
if DEBUG then                                                                                                                    ;*[004]
   PRINT 'IN EXPECTB'
   PRINT 'NEXTB.IN.A IS ':NEXTB.IN.A
END                                                                                                                              ;*[004]
SKIPB = $TRUE
LAST = NEXTB.IN.A - 1
for I = 1 TO LAST
   GOSUB FORMAT
NEXT I
SKIPB = $FALSE
RETURN


**-- FlushA
FlushA:
COUNT.DISC += 1
SKIPB = $TRUE
LOOP
   GOSUB FORMAT
   GOSUB DEL.RECORDA
until not(DISPLAYA)
REPEAT
RETURN


**-- FlushB
FlushB:
COUNT.DISC += 1
SKIPA = $TRUE
LOOP
   GOSUB FORMAT
   GOSUB DEL.RECORDB
until not(DISPLAYB)
REPEAT
RETURN


**-- FlushAB
FlushAB:
SKIPA = 0
SKIPB = 0
LOOP
   GOSUB FORMAT
while RECORDA and RECORDB
REPEAT
RETURN


**-- FORMAT
FORMAT:
if DEBUG then                                                                                                                    ;*[005]
   PRINT "[DEBUG] IN FORMAT"                                                                                                     ;*[005]
END                                                                                                                              ;*[005]
begin case
   case not(SKIPA OR SKIPB)
      if DEBUG then                                                                                                              ;*[005]
         PRINT "[DEBUG] LINES IDENTICAL"                                                                                         ;*[005]
      END                                                                                                                        ;*[005]
      if not(SHOW.DISC) then
         LINEA = ('0000':PTRA)[4]:' ':FMT(DISPLAYA<1>[1,WIDTH],FMT)
         LINEB = ('0000':PTRB)[4]:' ':FMT(DISPLAYB<1>[1,WIDTH],FMT)
         PRINT TRIMB(LINEA:' ':LINEB)
      END
      PTRA += 1
      PTRB += 1
      GOSUB DEL.RECORDA
      GOSUB DEL.RECORDB
      DEL DISPLAYA<1>
      DEL DISPLAYB<1>
   case SKIPA
      LINEB = ('0000':PTRB)[4]:' ':FMT(DISPLAYB<1>[1,WIDTH],FMT)
      PRINT SPACE(WIDTH+5):'>':TRIMB(LINEB)
      BS.NOT.IN.A += 1
      PTRB += 1
      GOSUB DEL.RECORDB
      DEL DISPLAYB<1>
   case SKIPB
      LINEA = ('0000':PTRA)[4]:' ':FMT(DISPLAYA<1>[1,WIDTH],FMT)
      PRINT LINEA:'<'
      PTRA += 1
      AS.NOT.IN.B += 1
      GOSUB DEL.RECORDA
      DEL DISPLAYA<1>
   case 1
END CASE
EOFA = LEN(RECORDA) eq 0
EOFB = LEN(RECORDB) eq 0
if DISPOSITION eq 'L' then
*[005]        PRINTER OFF
*[005]        PRINT '*':
*[005]        PRINTER ON
   CRT '*':                                                                                                                      ;*[005]
END
RETURN
*

KEYWORDS:
uPARM = upcase(PARM)
DISPOSITION = 'C'
SHOW.DISC = $FALSE
FORM.NAME = ''
ERROR = $FALSE

if LEN(uPARM) eq 0 then
   ERROR = $TRUE
   RETURN
END

DEBUG = $TRUE                                                                                                                    ;*[005]
LOCATE '-DEBUG' IN uPARM<1> SETTING POS ELSE                                                                                     ;*[005]
   DEBUG = $FALSE                                                                                                                ;*[005]
END                                                                                                                              ;*[005]
if DEBUG then
   PRINT "[DEBUG] IN DEBUG MODE"                                                                                                 ;*[005]
   DEL uPARM<POS>                                                                                                                ;*[005]
   DEL PARM<POS>                                                                                                                 ;*[005]
END

FOUND = $TRUE
LOCATE '-DISP' IN uPARM<1> SETTING POS ELSE FOUND = $FALSE
if FOUND then
   DISPOSITION = uPARM<POS+1>
   DEL uPARM<POS+1>
   DEL PARM<POS+1>
   DEL uPARM<POS>
   DEL PARM<POS>
   if DISPOSITION eq '' then
      ERROR = $TRUE
      PRINT 'Argument for -DISP missing.'
      RETURN
   END
END

FOUND = $TRUE
LOCATE '-SD' IN uPARM<1> SETTING POS ELSE FOUND = $FALSE
if FOUND then
   DEL uPARM<POS>
   DEL PARM<POS>
   SHOW.DISC = $TRUE
   crt "Show discrepancies only."
END

locate "-PRESERVE" in uPARM<1> setting POS then
   PreserveWhiteSpace = 1
   del uPARM<POS>
   crt "Preserve white space."
   del PARM<POS>
end else
   PreserveWhiteSpace = 0
end

FOUND = $TRUE
FORM.NAME = "NECLASER"
LOCATE '-FORM' IN uPARM<1> SETTING POS ELSE FOUND = $FALSE
if FOUND then
   FORM.NAME = uPARM<POS+1>
   DEL uPARM<POS+1>
   DEL PARM<POS+1>
   DEL uPARM<POS>
   DEL PARM<POS>
   crt "Form queue ":FORM.NAME
END

FOUND = $TRUE
LOCATE '-RES' IN uPARM<1> SETTING POS ELSE FOUND = $FALSE
if FOUND then
   Resolution = uPARM<POS+1>
   DEL uPARM<POS>
   DEL PARM<POS>
   DEL uPARM<POS>
   DEL PARM<POS>
   if Resolution eq '' then
      STOP 'Parameter for -RES option missing.'
   END
   if not(NUM(Resolution)) then
      STOP 'Expected numeric operand for -RES found: ':Resolution
   END
END ELSE
   Resolution = 3
END
RES.MINUS.1 = Resolution - 1
if DEBUG then                                                                                                                    ;*[004]
   PRINT 'Resolution: ':Resolution
END                                                                                                                              ;*[004]
crt "Match resolution set to: ":Resolution

FOUND = $TRUE
LOCATE '-BUFF' IN uPARM<1> SETTING POS ELSE FOUND = $FALSE
if FOUND then
   BUFFER.SIZE = uPARM<POS+1>
   DEL uPARM<POS>
   DEL PARM<POS>
   DEL uPARM<POS>
   DEL PARM<POS>
END ELSE
   BUFFER.SIZE = 2000
END
if DEBUG then                                                                                                                    ;*[004]
   PRINT 'BUFFER.SIZE: ':BUFFER.SIZE
END                                                                                                                              ;*[004]
crt "Lookup buffer set to: ":BUFFER.SIZE

if DEBUG then PRINT "uPARM: ":uPARM
FOUND = $TRUE
LOCATE '-IGNORE' IN uPARM<1> SETTING POS ELSE FOUND = $FALSE
if FOUND then
   IGNORE.TEXT = uPARM<POS+1>
   DEL uPARM<POS>
   DEL PARM<POS>
   DEL uPARM<POS>
   DEL PARM<POS>
   crt "Ignoring ":IGNORE.TEXT
END ELSE
   IGNORE.TEXT = ""
END
if DEBUG then                                                                                                                    ;*[004]
   PRINT 'IGNORE.TEXT: ':IGNORE.TEXT
END                                                                                                                              ;*[004]

MORE.PARMS = LEN(PARM) GT 0
PARM := ''
VOC.RECS.PTR = 0
REC.PTR = 0
OPEN '','VOC' TO VOC.FILE ELSE NULL                                                                                              ;*[005]
MAT FILENAMES = ""
for I = 1 TO 4
   if not(MORE.PARMS) then exit                                                                                                  ;*[006]
   REMOVE ITEM FROM PARM SETTING MORE.PARMS
*[990707]    READ VOC.REC FROM VOC.FILE, ITEM ELSE VOC.REC = ''
   read VOC.REC from VOC.FILE, ITEM else                                                                                      ;*[990707]
      read VOC.REC from VOC.FILE, upcase(ITEM) then                                                                           ;*[990707]
         ITEM = upcase(ITEM)                                                                                                  ;*[990707]
      end else                                                                                                                ;*[990707]
         VOC.REC = ""                                                                                                         ;*[990707]
      end                                                                                                                     ;*[990707]
   end                                                                                                                        ;*[990707]
   Type = field(VOC.REC<1>," ",1)
   if (Type eq 'F') or (Type eq "DIR") then
      VOC.RECS.PTR += 1
      if VOC.RECS.PTR GE 3 then
         ERROR = $TRUE
         PRINT 'Number of filenames not to exceed two.'
         RETURN
      END
      VOC.RECS(VOC.RECS.PTR) = VOC.REC
      FILENAMES(VOC.RECS.PTR) = ITEM
   END ELSE
      REC.PTR += 1
      if REC.PTR GE 3 then
         ERROR = $TRUE
         PRINT 'Number of recordnames not to exceed two.'
         RETURN
      END
      RECORDNAMES(REC.PTR) = ITEM
   END
NEXT I
if VOC.RECS.PTR eq 1 then FILENAMES(2) = FILENAMES(1)

if VOC.RECS.PTR eq 1 then
   FILENAMEA   = FILENAMES(1)
   VOC.RECA    = VOC.RECS(1)
   FILENAMEB   = FILENAMEA
   VOC.RECB    = VOC.RECA
END ELSE
   FILENAMEA   = FILENAMES(1)
   VOC.RECA    = VOC.RECS(1)
   FILENAMEB   = FILENAMES(2)
   VOC.RECB    = VOC.RECS(2)
END
if REC.PTR eq 1 then RECORDNAMES(2) = RECORDNAMES(1)
RECORDNAMEA = RECORDNAMES(1)
RECORDNAMEB = RECORDNAMES(2)

RETURN


USAGE:

crt "USAGE: CMPF fileAB recordA recordB [args]"
crt "       CMPF fileA fileB recordAB [args]"
crt "       CMPF fileA recordA fileB recordB [args]"
crt
crt "   args are as follows:"
crt
crt "     -SD          Forces only the differences between the"
crt "                  two files to be shown (saves paper and time)."
crt "     -DISP disp   This is the disposition of the report:"
crt "        L - To the lineprinter."
crt "        C - To the CRT (default)."
crt "        A - To the aux port. (arch.)"
crt "     -FORM        The form name to spool to (default SUITEJ)."
crt "     -RES n       The number of lines necessary to complete a"
crt "                  match during look-up.  Default 3."
crt "     -BUFF m      The number of lines that will be buffered at"
crt "                  any time.  All compares are processed"
crt "                  sequentially.  Default 2000."
crt "     -HELP        Displays this information."
crt "     -IGNORE xxxx This is a text string to ignore during the"
crt "                  compare process. This is usually text change"
crt "                  markers."
RETURN

DEL.RECORDA:
DEL RECORDA<1>
if EOF.FILE.A then RETURN
REMOVE LINEA FROM SOURCEA SETTING MORE.SOURCEA
EOF.FILE.A = not(MORE.SOURCEA)
if EOF.FILE.A then RETURN
GOSUB PROCESS.LINEA
RETURN

DEL.RECORDB:
DEL RECORDB<1>
if EOF.FILE.B then RETURN
REMOVE LINEB FROM SOURCEB SETTING MORE.SOURCEB
EOF.FILE.B = not(MORE.SOURCEB)
if EOF.FILE.B then RETURN
GOSUB PROCESS.LINEB
RETURN

PROCESS.LINEA:
DISPLAYA<-1> = LINEA:' '
CONVERT ' ' TO '' IN LINEA
LINEA = change(LINEA,IGNORE.TEXT,"")
if LEN(LINEA) eq 0 then
   RECORDA := @FM
END ELSE
   RECORDA<-1> = LINEA
END
RETURN

PROCESS.LINEB:
DISPLAYB<-1> = LINEB:' '
CONVERT ' ' TO '' IN LINEB
LINEB = change(LINEB,IGNORE.TEXT,"")
if LEN(LINEB) eq 0 then
   RECORDB := @FM
END ELSE
   RECORDB<-1> = LINEB
END
RETURN

END
