;COMPBIN.ASM
;MOD OF COMPARE.ASM FOR BINARY FILES
;INCLUDES REPORTING AND ACCEPTANCE OF INSERTIONS,
;DELETIONS, ETC.
;
;COMPARE.ASM
;11/??/77 ORIGINALLY WRITTEN BY WARD CHRISTENSEN
;12/31/77 ADD PICKUP OF SECOND FILENAME IF BLANK
;01/08/77 ADD SEQIO MACLIB TO READ BIG BLOCKS
;09-09-82 MOD TO COMPBIN BY RUSS BAKKE
;
	MACLIB	SEQIO
BSIZE	EQU	1024	;DISK BUFFER SIZE (TIMES 2)
	ORG	100H
;
;MACRO DEFS
PRINT	MACRO	?L
	LOCAL	Z
	CALL	Z
	IRP	?M,<?L>
	DB	?M
	ENDM
	DB	'$'
Z	POP	D
	MVI	C,@MSG
	CALL	@BDOS
	ENDM
;
GETF	MACRO	?B,?P,?F,?E,?L,?N
	LOCAL	Q,R,S
	IF	NOT NUL ?B
	LXI	H,?B
	ENDIF
	IF	NOT NUL ?P
	SHLD	?P
	ENDIF
	IF	NOT NUL ?L
	LXI	B,?L
	ENDIF
Q	PUSH	B
	PUSH	H
	CALL	?F
	POP	H
	POP	B
	MOV	M,A
	JZ	R	;EOF
	INX	H
	DCX	B
	MOV	A,B	;DONE?
	ORA	C
	JNZ	Q	;NO
	JMP	S
;
R	MVI	A,1	;SET EOF FLAG
	STA	?E
;
S	SHLD	?N	;SAVE EOF ADDR
	ENDM
;
REFILL	MACRO	?B,?P,?E,?C
	LOCAL	P
	PUSH	D
	SHLD	?C
	XCHG
	LXI	B,8192	;BUFFER SIZE
	LHLD	?P
	PUSH	H
	MOV	A,H	;NEGATE HL
	CMA
	MOV	H,A
	MOV	A,L
	CMA
	MOV	L,A
	INX	H
	DAD	D	;ADD DE
	LXI	D,?B
	DAD	D	;ADD BUFST
	SHLD	?C
	POP	H
P	MOV	A,M	;MOVE CHAR
	STAX	D
	DCX	B	;COUNT IT
	INX	D	;MOVE POINTERS
	INX	H
	CALL	?E
	JNZ	P
	ENDM
;
CKEOB	MACRO	?E
	PUSH	D
	LXI	D,?E
	CALL	CMPHD
	POP	D
	ENDM
;
CKEOF	MACRO	?E
	PUSH	D
	XCHG
	LHLD	?E
	XCHG
	CALL	CMPHD
	POP	D
	ENDM
;
;COMPBIN.ASM - COMPARES 2 BINARY FILES
;
;COMMAND FORMAT: COMPBIN NAME1 NAME2
;	IF NAME2 = NAME1 BUT IS ON B DISK,
;	JUST TYPE: COMPBIN NAME1 B:
;
	LXI	SP,STACK	;INIT STACK
;
	PRINT	<'COMPBIN.COM 09-09-82',0DH,0AH>
;
;IF THE SECOND FCB IS BLANK,
;MOVE IN THE NAME FROM THE FIRST
;
	LDA	@TFCB+17
	CPI	' '
	JNZ	MOVE2	;NOT BLANK
	MVI	B,11
	LXI	D,@TFCB+1
	LXI	H,@TFCB+17
	CALL	MOVER
;
;'DECLARE' BOTH FCB'S
;
MOVE2	FILE	INFILE,FILE1,,1,,BSIZE
	FILE	INFILE,FILE2,,2,,BSIZE
;
;COMPARE THE 2 FILES
;
;FIRST, READ 8K INTO FIRST BUFFER
	GETF	BUF1ST,OK1,GETFILE1,EOF1FG,8192,EOF1
;READ 8K INTO SECOND BUFFER
	GETF	BUF2ST,OK2,GETFILE2,EOF2FG,8192,EOF2
;
;NOW START COMPARE
	LXI	H,BUF1ST
	LXI	D,BUF2ST
COMP	LDAX	D
	CMP	M
	JNZ	DIFFER
	INX	H
	INX	D
;ARE WE AT START OF NEW 8 BYTE BLOCK?
;(IN ORDER TO HANDLE MOVING POINTERS, WE
;KEEP POINTERS TO KNOWN GOOD DATA IN "OK1"
;& "OK2" TO THE START OF THE LAST GOOD 8
;BYTE BLOCK.  THIS BLOCK ALWAYS STARTS ON
;XXX0H ADDR IN FILE 1; IT MAY NOT IN FILE 2.)
;
	MOV	A,L
	ANI	7
	CZ	EOBL
;
;ARE WE AT EOF (WHICH IS EITHER EOF LOCN
;OR END OF BUFFER)?
	CALL	CKEOF1
	JNZ	COMP1	;NO
	LDA	EOF1FG
	ORA	A
	JNZ	EOFFND	;YES AND EOF LOADED, QUIT
	CALL	EOBUF1
;
COMP1	CALL	CKEOF2
	JNZ	COMP2	;NO
	LDA	EOF2FG
	ORA	A
	JNZ	EOFFND
	CALL	EOBUF2
;
COMP2	JMP	COMP
;
;FOUND A DIFFERENCE;
;IF EOF IS NOT IN BUFFER, FIRST FORCE
;BUFFER FILL IN ORDER TO AVOID HITTING
;EOBUF IN DIFFERENCE PROCESSING
DIFFER	LDA	EOF1FG
	ORA	A	;TEST 0
	JNZ	DIFF1
;NOW SEE IF AT START OF BUFFER
	PUSH	H
	LHLD	OK1
	CKEOB	BUF1ST
	POP	H
	CNZ	EOBUF1
DIFF1	LDA	EOF2FG
	ORA	A
	JNZ	DIFF2
	XCHG
	PUSH	H
	LHLD	OK2
	CKEOB	BUF2ST
	POP	H
	XCHG
	CNZ	EOBUF2
;
;IF WE ARE NOT AT START OF BLOCK IN FILE 1,
;STEP (STOP AT EOF)
DIFF2	XCHG
	SHLD	CURR2	;SAVEDE
	XCHG
	MVI	C,8	;REPEAT 8 TIMES
DIFF3	INX	H;MOVE OFF SOB
	CALL	GOSOB	;GO TO NEXT SOB
	XCHG
	LHLD	CURR2	;RESTORE DE
	XCHG
;
;NOW SEE IF WE ARE AT EOF IN EITHER FILE
	CALL	CKEOF1
	JZ	DIFEOF
	CALL	CKEOF2
	JZ	DIFEOF
;
;NOW FIND EXTEND OF DIFFERENCE.
;COMPARE CURRENT BLOCK IN FILE 1 TO
;FILE 2.
;HL POINTS TO CURRENT BLOCK IN FILE 1,
;DE IN FILE 2
;INC DE UP TO 64 TIMES, COMPARING BYTE TO HL.
;IF A MATCH IS FOUND:
;  INC HL ALSO; LOOK FOR 8 MATCHES IN A ROW.
;  IF NOT FOUND RESTORE HL & CONTINUE. 
;  IF FOUND, EXIT.
;IF 64 INCREMENTS HIT,
;INC HL BY 8 & REPEAT TOTAL OF 8 TIMES.
;IF STILL NOT FOUND, GIVE UP.
;IF EOF HIT, EXIT.
;
	MVI	B,64	;8 BLOCKS OF 8 BYTES
;
DIFF4	LDAX	D
	CMP	M
	CZ	BYTEM
	JZ	MATCH
	INX	D
	CALL	CKEOF2
	JZ	DIFEOF
	DCR	B
	JNZ	DIFF4
;
;NOT FOUND, NEXT BLOCK
	DCR	C
	JNZ	DIFF3
;
;STILL NO MATCH FOUND.  PRINT 8 BLOCKS
;FROM EACH BUFFER & EXIT.
;
;WE HAVE A DIFFERENCE AND ARE AT EOF IN A FILE
;PRINT FROM "LAST" POINTER TO EOF IN BOTH BUFFERS
;(STOP AFTER 8 BLOCKS)
DIFEOF	LDA	ERFLG
	ORA	A	;TEST ERROR FLAG
	JNZ	DIFE1
	INR	A	;SET IT
	STA	ERFLG
	PRINT	<'FILES UNEQUAL',0DH,0AH>
DIFE1	PRINT	<'****** FILE 1:',0DH,0AH>
;PRINT FILE 1 FROM "LAST OK"
	LHLD	EOF1
	XCHG
	LHLD	OK1
	CALL	PRBUF
	PRINT	<'*** FILE 2:',0DH,0AH>
	LHLD	EOF2
	XCHG
	LHLD	OK2
	CALL	PRBUF
	JMP	EXIT
;
;BYTEM--HAVE MATCHING BYTE, MOVING DE IN
;ONE BUFFER, MATCHES HL IN OTHER BUFFER.
;WANT TO FIND 7 MORE MATCHING BYTES IN A ROW.
;RET Z IF SO.
BYTEM	PUSH	H
	PUSH	D
	PUSH	B
	MVI	B,7	;MATCH 7 BYTES
BML	INX	H
	INX	D
	LDAX	D
	CMP	M
	JNZ	BM2
	DCR	B
	JNZ	BML
;HAVE 7 MORE MATCHED BYTES (& Z SET)
BM2	POP	B
	POP	D
	POP	H
	RET
;
;PRBUF--PRINT BUFFER (AT HL) FOR 9 BLOCKS OR EOF
;ENTER WITH EOF ADDR IN DE
PRBUF	MVI	B,9
PRBUF1	PUSH	B
	CALL	PRBLK	;PRINT BLOCK
	POP	B
	JZ	PREOF	;AT EOF?
	DCR	B	;COUNT BLOCK
	JNZ	PRBUF1
	RET
;
;PREOF--AT EOF IN PRINT
PREOF	PRINT	<'*EOF',0DH,0AH>
	RET
;
;PRBLK--PRINT BLOCK FROM HL
;LIMIT IN DE--RET Z IF HIT
PRBLK	SHLD	TEMP	;SAVE HL
MVI	B,8	;8 BYTES
PRBLK1	CALL	CMPHD
	RZ
	MOV	A,M
	INX	H
;DISPLAY A IN HEX
	PUSH	PSW
	RRC		;SHIFT RIGHT 4
	RRC
	RRC
	RRC
	CALL	TAD
	POP	PSW
	CALL	TAD
	MVI	A,' '
	CALL	TYPE
	DCR	B
	JNZ	PRBLK1
;
;NOW DISPLAY LINE IN ASCII ('.' IF NOT PRINTABLE)
	LHLD	TEMP
	MVI	B,8	;8 BYTES
PRBLK2	MOV	A,M
	INX	H
	CPI	80H
	JNC	NOPR
	CPI	20H
	JNC	PRBLK3
;
NOPR	MVI	A,'.'	;SUB '.' FOR NON-PRINTING
PRBLK3	CALL	TYPE
	DCR	B
	JNZ	PRBLK2
	CALL	CRLF
	INR	A	;CLEAR Z FLAG
	RET
;
;TAD--TRANSLATE HEX TO ASCII & DISPLAY
TAD	ANI	0FH	;MASK
	ADI	90H
	DAA
	ACI	40H
	DAA
	CALL	TYPE
	RET
;
CRLF	MVI	A,CR
	CALL	TYPE
	MVI	A,LF
;
;TYPE--DISPLAY CHAR IN A
TYPE	PUSH	B
	PUSH	D
	PUSH	H
	PUT	CON
	POP	H
	POP	D
	POP	B
	RET
;
;MATCH:  HAVE A MATCHED BLOCK.  HL & DE POINT
;TO START OF BLOCK.
;PRINT FROM OK1 & OK2 TO END OF DIFF.
;UPDATE OK1 & OK2 & RETURN TO COMPARE.
MATCH	PUSH	H
	PUSH	D
	SHLD	CURR1	;TEMP STORAGE
	XCHG
	SHLD	CURR2
;
;PRINT THE BUFFERS
	LDA	ERFLG
	ORA	A	;TEST ERROR FLAG
	JNZ	MAT1
	INR	A	;SET IT
	STA	ERFLG
	PRINT	<'FILES UNEQUAL',0DH,0AH>
MAT1	PRINT	<'****** FILE 1:',0DH,0AH>
	LHLD	CURR1
	XCHG
;DE POINTS TO END OF BUFF1 TO BE PRINTED
	LHLD	OK1
	CALL	PRTOLM
	PRINT	<'*** FILE 2:',0DH,0AH>
	LHLD	CURR2	;NOW BUFF 2
	XCHG
	LHLD	OK2
	CALL	PRTOLM
;
;NOW UPDATE OK1, OK2, POINTERS
	LHLD	CURR1
	SHLD	OK1
	LHLD	CURR2
	SHLD	OK2
	POP	D
	POP	H
	JMP	COMP	;RETURN TO COMPARE LOOP
;
;PRTOLM--PRINT FROM HL TO LIMIT IN DE
PRTOLM	CALL	PRBLK
	JNZ	PRTOLM	;NOT DONE
	RET
;
;EOBL--MOVE POINTERS TO "LAST OK BLOCKS"
EOBL	PUSH	H
	PUSH	D
	CALL	RETSBL	;BACK UP TO PREVIOUS LINE
	SHLD	OK1	;SAVE IT
	XCHG
	CALL	RETSBL
	SHLD	OK2
	POP	D
	POP	H
	RET
;
;EOBUF1-END OF BUFFER 1
;COPY FROM "LAST OK BLOCK" POINTER THRU END
;OF BUFFER, TO START OF BUFFER;
;REFILL REST OF BUFFER
;KEEP POINTER TO CURRENT BYTE (NOW AT EOBUF)
EOBUF1	REFILL	BUF1ST,OK1,CKEOB1,CURR1
;
;NOW FILL BUFFER
	XCHG
	GETF	,,GETFILE1,EOF1FG,,EOF1
;
;SET UP POINTER OK1
	LXI	H,BUF1ST
	SHLD	OK1
	LHLD	CURR1	;NEW BUFFER PTR
	POP	D	;RECOVER
	RET
;
;EOBUF2--END OF BUFFER2
EOBUF2	XCHG
	REFILL	BUF2ST,OK2,CKEOB2H,CURR2
	XCHG
	GETF	,,GETFILE2,EOF2FG,,EOF2
	LXI	H,BUF2ST
	SHLD	OK2
	LHLD	CURR2
	XCHG
	POP	H
	RET
;
;CKEOB1--SEE IF HL IS AT END OF BUFF1
;(RET Z IF SO)
CKEOB1	CKEOB	BUF1EN
	RET
;
;CKEOF1--SEE IF HL IS AT END OF FILE1
;(EOBUF OR LOADED EOF)
;(RET Z IF SO)
CKEOF1	CKEOF	EOF1
	RET
;
;CKEOF2--SEE IF DE IS AT END OF FILE2
CKEOF2	XCHG
	CKEOF	EOF2
	XCHG
	RET
;
;CKEOB2H--SEE IF HL IS AT END OF BUFF2
CKEOB2H	CKEOB	BUF2EN
	RET
;
;EOFFND--AT EOF IN VALID COMPARE
;IF NO ERROR FLAG, PRINT OK & EXIT
;ELSE JUST EXIT
EOFFND	LDA	ERFLG
	ORA	A	;SET FLAGS
	JZ	AOK
	JMP	EXIT
;
;A-OK - FILES MATCH
;
AOK	PRINT	'FILES MATCH'
EXIT	RST	0	;RET TO CP/M
;
ERXIT	POP	D	;GET MESSAGE
	MVI	C,@MSG
	CALL	@BDOS
	JMP	EXIT
;
;RETSBL--RET HL TO START OF BLOCK
RETSBL	DCX	H	;BACK TO PREV BLOCK
	MOV	A,L
	ANI	0F8H
	MOV	L,A
	RET
;
;GOSOB--INC HL TO START OF NEXT BLOCK OR EOF
;IN FILE 1
GOSOB	MOV	A,L
	ANI	7
	RZ	;THERE
	INX	H
	CALL	CKEOF1
	RZ
	JP	GOSOB
;
;CMPHD--COMPARE HL TO DE
;RETS Z IF EQ, C IF HL>DE
CMPHD	MOV	A,D
	SUB	H
	RNZ
	MOV	A,E
	SUB	L
	RET
;
;MOVE FROM (DE) TO (HL) LENGTH IN B
MOVER	LDAX	D
	MOV	M,A
	INX	D
	INX	H
	DCR	B
	JNZ	MOVER
	RET
;
;DATA STORAGE
	DS	80	;STACK
STACK	EQU	$
OK1	DS	2	;LAST VALID LINE, FILE1
OK2	DS	2
CURR1	DS	2	;CURRENT LINE IN SEARCH
CURR2	DS	2
ERFLG	DB	0	;ERROR FLAG
EOF1	DS	2	;EOF ADDR
EOF2	DS	2
EOF1FG	DB	0	;EOF FLAGS
EOF2FG	DB	0
TEMP	DS	2
	ORG	($+15) AND 0FFF0H	;TO 16 BYTE BOUNDARY
BUF1ST	DS	8192
BUF1EN
BUF2ST	DS	8192
BUF2EN
BUFFERS	EQU	$
MEMSIZE	EQU	BUFFERS+@NXTB
	END
