;********************************************************
;*							*
;*		BINARY FILE COMPARE UTILITY		*
;*							*
;********************************************************
;
;
;	Portions Copyright (C) 1980
;
;	Bill Bolton,
;	Software Tools,
;	P.O. Box 80,
;	Newport Beach,,
;	NSW, 2106
;	AUSTRALIA
;
;	History:
;
;	1/Oct/77	 Version 1.00 by Ward Christensen
;
;	31/Jan/80	 Version 1.10 by Bill Bolton, improved
;			 error messages and optional file display
;
;	6/Sept/80	 Version 1.20 by Bill Bolton, copy second
;			 filename from first, if second blank
;
;
	MACLIB	MACRO3		;OFTWARE TOOLS SPECIAL MACROS
;
	ORG	100H
;
	CALL	START	;PRINT ID MESSAGE
;
	DB	0DH,0AH,'Binary File Compare '
	DB	'Utility : Version 1.20'
	DB	0DH,0AH
	DB	'DDH Compatible Display by Bill Bolton'
	DB	0DH,0AH
	DB	'Software Tools, Australia'
	DB	0DH,0AH,'$'
;
START:
	POP	D
	CALL	PRINT$MESSAGE
	LXI	H,0
	DAD	SP	;HL=CP/M'S STACK
	SHLD	STACK	;SAVE IT
	LXI	SP,STACK ;SET UP NEW STACK
;
	LDA	FCB+17	;POINT TO FILENAME IN SECOND FCB 
	CPI	' '	;EMPTY?
	JNZ	SAVE$NAME ;NO, JUST MOVE IT
	LXI	D,FCB+1	;YES, POINT TO FILENAME IN FIRST FCB
	LXI	H,FCB+17 ;POINT TO FILENAME IN SECOND FCB
	MVI	B,11	;LENGTH OF FILE NAME
	CALL	MOVEIT	;MOVE FILENAME
;
;MOVE THE SECOND FCB SO OPENING THE FIRST
;WON'T WIPE IT OUT
;
SAVE$NAME:
	CALL	MOVE$FCB
;
;PRINT OPENING MESSAGE
;
	LXI	D,FIRST
	CALL	PRINT$MESSAGE
	CALL	CONSOLE
	CPI	'Y'
	JNZ	BLANK
	MVI	A,0FFH
	STA	PRFLAG
BLANK:
	LXI	D,NEWLINE
	CALL	PRINT$MESSAGE
;
;OPEN BOTH FILES, EXITING IF EITHER DOESN'T EXIST
;
	CALL	OPEN$FILES
;
;READ EACH FILE 1 BYTE AT A TIME, COMPARING THEM
;
COMPARE:
	CALL	READ1
	MOV	B,A	;SAVE CHAR READ
	CALL	READ2
	CMP	B	;SAME?
	JZ	COMPARE
;
;UNEQUAL COMPARE
;
	LXI	D,UNEQ$MSG
	CALL	PRINT$MESSAGE
	LHLD	SECTOR$COUNT
	DECOUT
	LXI	D,SPACEIT
	CALL	PRINT$MESSAGE
	LXI	D,BYTE$MSG
	CALL	PRINT$MESSAGE
	LDA	BUFAD1	;GET FIRST BUFF ADDR
	SUI	81H	;SUBTRACT BIAS
	CALL	XO	;PRINT IN HEX
	LXI	D,SPACEIT
	CALL	PRINT$MESSAGE
	CALL	CONSTAT
	ORA	A
	JZ	COMPARE
	CALL	CONSOLE
	CPI	3		;IS ^C?
	JZ	EXIT
	CPI	20H		;IS IT SPACE?
	JNZ	COMPARE
EXIT:
	LHLD	STACK	;GET CP/M'S STACK
	SPHL		;RESTORE IT
	RET		;..AND RETURN
;
ERXIT:
	POP	D	;GET MESSAGE
	CALL	PRINT$MESSAGE
	JMP	EXIT
;
UNEQ$MSG:
	DB	0DH,0AH,'++ FILES UNEQUAL IN SECTOR    $'
;
BYTE$MSG:
	DB	'AT BYTE    $'
;
SPACEIT:
	DB	'    $'
;
NEWLINE:
	DB	0DH,0AH,'$'
;
FIRST:	DB	0DH,0AH,'Do you want file 1 printed '
	DB	'as it is compared ?'
	DB	'....[Y/N] (CR="N")   ' ,'$'
;
; * * * * * * * * * * * * * * * * * * * * * * * *
;						*
;		SUBROUTINES			*
;						*
; * * * * * * * * * * * * * * * * * * * * * * * *
;
PRINT$MESSAGE:
	MVI	C,STRING
	JMP	BDOS	;PRINT, RETURN
;
PRINT$HEX$HL:
	MOV	A,H
	CALL	XO
	MOV	A,L
	CALL	XO
	MVI	A,' '
;FALL INTO 'TYPE'
;
TYPE:
	PUSH	B
	PUSH	D
	PUSH	H
	MOV	E,A	;AS REQ'D BY CP/M
	MVI	C,WRCON
	CALL	BDOS
	POP	H
	POP	D
	POP	B
	RET
;
XO:
	PUSH	PSW	;HEX OUT
	RAR
	RAR
	RAR
	RAR
	CALL	NIBBL	;LEFT NIBBL
	POP	PSW
NIBBL:
	ANI	0FH
	CPI	10
	JC	ISNUM
	ADI	7
ISNUM:
	ADI	'0'
	JMP	TYPE
;
OPEN$FILES:
	LXI	D,FCB
	MVI	C,OPEN
	CALL	BDOS
	INR	A	;OPEN OK?
	JNZ	FILE$1$OPEN
	CALL	ERXIT
	DB	0DH,0AH,'***** CANT OPEN FILE 1 ***** ',0DH,0AH,'$'
FILE$1$OPEN:
	LXI	D,FCB2
	MVI	C,OPEN
	CALL	BDOS
	INR	A
	RNZ
	CALL	ERXIT
	DB	0DH,0AH,'***** CANT OPEN FILE 2 *****',0DH,0AH,'$'
;
READ1:
	LHLD	BUFAD1	;TIME TO READ?
	DCR	H	;AT 100H?
	JNZ	NO$READ$1
;
;PHYSICALLY READ FILE 1
;
	LXI	H,80H	;BUFFER ADDR
	SHLD	BUFAD1
	XCHG		;TO D,E
	MVI	C,STDMA
	CALL	BDOS
	LXI	D,FCB
	MVI	C,READ
	CALL	BDOS
	ORA	A	;OK?
	JNZ	EOF$FILE$1
	LHLD	SECTOR$COUNT
	INX	H
	SHLD	SECTOR$COUNT
NO$READ$1:
	LHLD	BUFAD1
	MOV	A,M	;GET CHAR
	INX	H	;POINT TO NEXT
	SHLD	BUFAD1
;
;REQUEST TO PRINT?
;
	MOV	L,A	;SAVE CHAR
	LDA	PRFLAG	;SET IF FILE 1 TO BE PRINTED ON CONSOLE
	CPI	0	;PRINT?
	MOV	A,L	;RESTORE CHAR FOR RET
	RZ		;RET IF NO PRINT REQ
;
;SHOW THE CHARACTER
;
	CPI	0DH	;C/R?
	JZ	SHOWIT
	CPI	0AH	;L/F?
	JZ	SHOWIT
	CPI	9	;TAB?
	JZ	SHOWIT
	CPI	' '	;PRINTABLE?
	JC	SHOWHEX	;HEX IF NOT PRINTABLE
	CPI	7FH
	JC	SHOWIT
;SHOW IN HEX
SHOWHEX:
	MVI	A,'('
	CALL	TYPE
	MOV	A,L	;GET CHAR
	MVI	A,')'
SHOWA:
	CALL	TYPE
	MOV	A,L	;GET CHAR
	RET
SHOWIT:
	MOV	A,L	;GET CHAR
	JMP	SHOWA
	RET
;
;GOT EOF ON FILE 1 - SHOULD GET EOF ON FILE 2
;
EOF$FILE$1:
	MVI	A,1	;GET FLAG
	STA	EOF$FLAG
	CALL	READ2	;SHOULD NOT RETURN
	CALL	ERXIT
	DB	0DH,0AH,0AH,'***** EOF ON FILE 1, NOT FILE 2 *****$'
;
READ2:
	LHLD	BUFAD2	;GET SECOND BUFF
	MOV	A,L	;GET ADDR
	CPI	(BUF2+128) AND 0FFH ;END?
	JNZ	NO$READ$2
;
;DO PHYSICAL READ ON FILE 2
;
	LXI	H,BUF2
	SHLD	BUFAD2
	XCHG		;TO DE
	MVI	C,STDMA
	PUSH	B	;SAVE CHAR FROM FILE 1
	CALL	BDOS
	LXI	D,FCB2
	MVI	C,READ
	CALL	BDOS
	POP	B
	ORA	A
	JNZ	EOF$FILE$2
NO$READ$2:
	LHLD	BUFAD2
	MOV	A,M	;GET CHAR
	INX	H	;POINT TO NEXT
	SHLD	BUFAD2	;SAVE BACK
	RET
;
EOF$FILE$2:
;SHOULD HAVE EOF ON 1, THUS EOF$FLAG SHOULD BE ON
	LDA	EOF$FLAG
	ORA	A	;ON?
	JNZ	A$OK
	CALL	ERXIT
	DB	0DH,0AH,0AH,'***** EOF ON FILE 2 BEFORE FILE 1 *****$'
A$OK:
	LXI	D,MATCH$MSG
	CALL	PRINT$MESSAGE
	LHLD	SECTOR$COUNT
	DECOUT
	CALL	ERXIT
	DB	' SECTORS .....',0DH,0AH,0AH,'$'
MATCH$MSG:
	DB	0DH,0AH,0AH,'..... FILES MATCH, LENGTH IS $'
;
MOVE$FCB:
	LXI	H,FCB2
	LXI	D,FCB+16
	MVI	B,16	;FCB LENGTH
MOVEIT:
	LDAX	D
	MOV	M,A
	INX	D
	INX	H
	DCR	B
	JNZ	MOVEIT
	RET
;
CONSTAT:
	MVI	C,11
	CALL	BDOS
	RET
;
CONSOLE:
	MVI	C,1
	CALL	BDOS
	RET
;
	DS	40	;STACK AREA
STACK:	DS	2
SECTOR$COUNT:
	DW	0
EOF$FLAG:
	DB	0	;=1 IF EOF FILE 1
FCB2:	DB	0,'XXXXXXXXYYY',0,0,0
	DB	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
PRFLAG:	DB	0
BUFAD1:	DW	80H+128	;INIT TO READ FIRST
BUFAD2:	DW	BUF2+128 ;LIKEWISE
BUF2:	DS	128
;
; * * * * * * * * * * * * * * * * * * * * * * * *
;						*
;BDOS/CBIOS EQUATES (VERSION 5)			*
;						*
RDCON	EQU	1	;			*
WRCON	EQU	2	;			*
STRING	EQU	9	;			*
OPEN	EQU	15	;0FFH=NOT FOUND		*
CLOSE	EQU	16	;   "	"		*
SRCHF	EQU	17	;   "	"		*
SRCHN	EQU	18	;   "	"		*
ERASE	EQU	19	;NO RET CODE		*
DELT	EQU	ERASE	;			*
READ	EQU	20	;0=OK, 1=EOF		*
WRITE	EQU	21	;0=OK, 1=ERR, 2=?,	*
;			0FFH=NO DIR SPC		*
MAKE	EQU	22	;0FFH=BAD		*
REN	EQU	23	;0FFH=BAD		*
STDMA	EQU	26	;			*
BDOS	EQU	5	;			*
FCB	EQU	5CH 	;			*
; * * * * * * * * * * * * * * * * * * * * * * * *
