;	COMPARE - CP/M FILE COMPARISON UTILITY
;
	ORG	0100H
	JMP	COMPARE
	DB	'(C) 1979 - N D H HAMMOND'
PRGNAME	DB	'COMPARE VSN 1.0 OF 3JAN80',0DH,0AH,'$'
;
;
	;SYSTEM ADDRESSES
WBOOTE	EQU	0000H	;REBOOT ADDRESS
SFCB	EQU	005CH	;SOURCE FILE CONTROL BLOCK
SFCBCR	EQU	SFCB+32	;NEXT RECORD COUNTER
TBUF	EQU	0080H	;SYSTEM DEFAULT BUFFER
	;CONSTANTS
CCPL	EQU	(3200H-2900H) SHR 8	;PAGES IN CCP
TRUE	EQU	0FFH
ETX	EQU	03H
LF	EQU	0AH
CR	EQU	0DH
EOM	EQU	'$'
;
;	MAIN PROGRAM
;
COMPARE	LXI	H,0	;SAVE OLD STACK POINTER
	DAD	SP
	SHLD	OLDSP
	LXI	SP,STACK
	LXI	D,PRGNAME
	CALL	WRITESTRING
	CALL	INITVAR
	CALL	SOURCEDISK
	CALL	OPENSOURCE
	CALL	LOADBUF
	CALL	COMPDISK
	CALL	OPENCOMP
REPEAT	CALL	COMPBUF
	LDA	FINISH
	CPI	TRUE
	JZ	ENDCOMP
	CALL	SOURCEDISK
	CALL	LOADBUF
	CALL	COMPDISK
	JMP	REPEAT
ENDCOMP	LDA	FIRST
	ORA	A
	JZ	EXIT
	LXI	D,COMPMSG
	CALL	WRITESTRING
EXIT	LHLD	OLDSP
	SPHL
	RET		;RETURN TO CP/M
;
;	SUBROUTINBS
;
INITVAR		;INITIALIZE VARIABLES
	XRA	A
	STA	FINISH
	;SET EXTENT TO CP/M CBASE
	LHLD	ENTRY+1	;HL:=FBASE
	MOV	A,H
	SBI	CCPL
	MOV	H,A		;HL:=CBASE
	MOV	A,L		;ENSURE EXTENT IS AT
	ANI	80H		;  A PAGE BOUNDARY
	MOV	L,A
	SHLD	EXTENT
	LXI	D,CFCB		;ZERO CFCB
	MVI	B,32
	XRA	A
ZCFB	STAX	D
	INX	D
	DCR	B
	JNZ	ZCFB
	LXI	D,CFCB
	LXI	H,SFCB+16	;GET COMP FILE NAME
	MVI	B,12
	CALL	COPYSTRING
	MVI	A,TRUE		;INITIALIZE VARIABLES
	STA	FIRST
	XRA	A
	STA	RECNO
	RET
;
;
OPENSOURCE	;OPEN SOURCE FILE
	LXI	D,SFCB
	CALL	OPENFILE
	CPI	0FFH
	JNZ	OPEN$OK
	MVI	B,1
	JMP	ERROR
OPEN$OK	XRA	A
	STA	SFCBCR
	RET
;
;
OPENCOMP	;OPEN COMP FILE
	LXI	D,CFCB
	CALL	OPENFILE
	CPI	0FFH
	JNZ	OP$OK
	MVI	B,1
	JMP	ERROR
OP$OK	XRA	A
	STA	CFCBCR
	RET
;
;
LOADBUF		;LOAD BUFFER FROM SOURCE FILE
	LXI	D,BUFFER
RDNXT	PUSH	D
	CALL	SETDMA
	LXI	D,SFCB
	CALL	READREC
	POP	D
	ORA	A
	JZ	RD$OK
	CPI	1
	JZ	EOF
	MVI	B,3
	JMP	ERROR
RD$OK	LXI	B,80H	;UPDATE BUFFER
	XCHG
	DAD	B
	LXI	B,EXTENT
	CALL	COMP
	XCHG
	JNZ	RDNXT
	RET
EOF	MVI	A,TRUE
	STA	FINISH
	XCHG
	SHLD	EXTENT
	RET
;
;
COMPBUF	;COMPARE BUFFER AND TEMP FILE
	LXI	D,TBUF		;TBUF FOR COMPFILE
	CALL	SETDMA
	LXI	D,BUFFER	;D IS BUFFER POINTER
COMPLP	PUSH	D
	CALL	COMPREC		;COMPARE 1 RECORD
	JC	TERMCK		;TERMCK IF EOF(COMP)
	POP	D
	LXI	B,80H		;UPDATE POINTER
	XCHG
	DAD	B
	LXI	B,EXTENT	;CHECK END OF BUFFER
	CALL	COMP
	XCHG
	JNC	COMPLP		;LOOP IF NOT PAST END
	MVI	B,5		;CHECK FOR COMPFILE TOO LONG
	LDA	FINISH
	ORA	A
	JZ	ERROR
	RET			;RETURN FOR NEXT BUFFER
TERMCK	POP	D
	LXI	B,EXTENT	;CHECK FOR COMP FILE TOO SHORT
	XCHG
	CALL	COMP
	MVI	B,7
	JNZ	ERROR
	LDA	FINISH
	ORA	A
	JZ	ERROR
	RET			;COMPARE COMPLETE
;
;
COMPREC	;COMPARE NEXT COMP FILE RECORD
	;WITH CORRESPONDING BUFFER RECORD
	;IN:	D:=BUFFER POINTER
	PUSH	D
	LXI	D,CFCB		;GET COMPFILE RECORD
	CALL	READREC
	POP	D
	ORA	A		;CHECK READ OK
	JZ	READ$OK
	CPI	1		;CHECK EOF
	JZ	EOFCOMP
	MVI	B,3		;REPORT ERROR
	JMP	ERROR
READ$OK	LXI	H,TBUF		;HL:=TBUF POINTER
	MVI	B,80H-1		;B:=BYTE COUNTER
CPRLP	LDAX	D
	CMP	M		;COMPARE BYTE
	PUSH	B
	PUSH	D
	PUSH	H
	CNZ	DIFFERENT
	POP	H
	POP	D
	POP	B	
	INX	H
	INX	D
	DCR	B
	JNZ	CPRLP		;LOOP UNTIL LAST BYTE
	LDA	RECNO		;INCREMENT RECORD NO
	INR	A
	STA	RECNO
	ORA	A		;CLEAR CARRY
	RET
EOFCOMP	STC			;SET CARRY TO INDICATE EOF
	RET
;
;
DIFFERENT	;REPORT NON MATCHING BYTES
		;IN	DE,HL:=^BYTES
		;	B:=7FH-BYTE NO IN RECORD
	PUSH	H		;SAVE PARAMETERS
	PUSH	D
	PUSH	B
	LDA	FIRST		;HEADINGS IF FIRST IS TRUE
	ORA	A
	JZ	NOHDG
	XRA	A		;FIRST:=FALSE
	STA	FIRST
	LXI	D,HDGMSG
	CALL	WRITESTRING
NOHDG	LDA	RECNO		;WRITE RECORD NO
	CALL	OUTHEX
	POP	B		;WRITE BYTE NO
	MVI	A,80H-1
	SUB	B
	CALL	OUTHEX
	POP	D		;WRITE SOURCE BYTE
	LDAX	D
	PUSH	PSW
	CALL	OUTHEX
	POP	PSW
	CALL	OUTASC
	POP	H		;WRITE COMP BYTE
	MOV	A,M
	PUSH	PSW
	CALL	OUTHEX
	POP	PSW
	CALL	OUTASC
	LXI	D,CRLFMSG
	CALL	WRITESTRING
	CALL	CHECKSTAT	;CHECK INPUT FROM OPERATOR
	ORA	A
	JNZ	EXIT		;ABORT IF SO
	RET
;
;
OUTHEX	;OUTPUT HEX VALUE OF ACCUMULATOR
	PUSH	PSW
	LXI	D,SPCMSG	;WRITE 4 SPACES
	CALL	WRITESTRING
	POP	PSW
	PUSH	PSW
	ANI	0F0H		;GET TOP 4 BITS
	RAR
	RAR
	RAR
	RAR
	CALL	OUTH		;PRINT
	POP	PSW		;GET BOTTOM 4 BITS
	ANI	00FH
	CALL	OUTH
	RET
;
;
OUTH	;PRINT 1 HEX CHAR
	CPI	0AH
	JC	NUM
	ADI	40H		;CONVERT 10..15 TO 'A'..'F'
	SUI	9
	JMP	WR
NUM	ADI	30H		;CONVERT 0..9 TO '0'..'9'
WR	MOV	E,A
	MVI	D,0
	CALL	WRITECHAR
	RET
;
;
OUTASC	;OUTPUT ASCII VALUE OF ACC
	PUSH	PSW
	LXI	D,SPCMSG
	CALL	WRITESTRING
	POP	PSW		;CHECK FOR GRAPHIC CHAR
	PUSH	PSW
	CPI	20H
	JC	NOTASC		;<' '
	CPI	7FH
	JNC	NOTASC		;>'\'
	MVI	D,0
	MVI	E,'"'		;WRITE "<CHAR>"
	CALL	WRITECHAR
	POP	PSW
	MVI	D,0
	MOV	E,A
	CALL	WRITECHAR
	MVI	D,0
	MVI	E,'"'
	CALL	WRITECHAR
	RET
NOTASC	LXI	D,NASCMSG		;WRITE ???
	CALL	WRITESTRING
	POP	PSW
	RET
;
;
COPYSTRING	;COPY STRING OF LENGTH B
		;FROM HL^ TO DE^
	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	COPYSTRING
	RET
;
;
ERROR		;PRINT ERROR MESSAGE
	LXI	D,OPMSG
	MOV	A,B
	CPI	1
	JZ	EPRINT
	LXI	D,REMSG
	CPI	3
	JZ	EPRINT
	LXI	D,FSMSG
	CPI	5
	JZ	EPRINT
	LXI	D,FCMSG
EPRINT	CALL	WRITESTRING
	JMP	EXIT
;
;
COMP		;COMPARE BC^ AND HL - SET FLAGS
	INX	B
	LDAX	B
	DCX	B
	CMP	H
	RNZ
	LDAX	B
	CMP	L
	RET
;
;
SOURCEDISK	;ADVISE OPERATOR, WAIT FOR RESPONSE,
	LXI	D,SDMSG
	CALL	WRITESTRING
	CALL	WAIT
	RET
;
;
COMPDISK	;ADVISE OPERATOR, WAIT FOR RESPONSE
	LXI	D,DDMSG
	CALL	WRITESTRING
	CALL	WAIT
	RET
;
;
WAIT	;WAIT FOR OPERATOR TO TYPE RETURN
	CALL	READCHAR
	CPI	03H
	JZ	WBOOTE
	CPI	CR
	JNZ	WAIT
	RET
;
;	CP/M COMMUNICATION ROUTINES
;
;
ENTRY	EQU	0005H	; BDOS ENTRY POINT
;
;
READCHAR	; READ A CHARACTER FROM CONSOLE
	MVI	C,1
	JMP	ENTRY
;
;
WRITECHAR	; WRITE A CHARACTER TO CONSOLE
	MVI	C,2
	JMP	ENTRY
;
;
WRITESTRING	; WRITE A STRING ON CONSOLE
	MVI	C,9
	JMP	ENTRY
;
;
CHECKSTAT	; CHECK CONSOLE INPUT STATUS
	MVI	C,11
	JMP	ENTRY
;
;
OPENFILE	; OPEN A NEW FILE
	MVI	C,15
	JMP	ENTRY
;
;
READREC		; READ NEXT 128 BYTE RECORD
	MVI	C,20
	JMP	ENTRY
;
;
SETDMA		; SET DMA ADDRESS FOR READ OR WRITE
	MVI	C,26
	JMP	ENTRY
;
;
;
;	DATA AREA
;
OLDSP	DS	2
CFCB	DS	33	;COMPARE FILE CONTROL BLOCK
CFCBCR	EQU	CFCB+32	;CURRENT RECORD COUNTER
FIRST	DS	1	;FIRST TIME THROUGH FLAG
RECNO	DS	1	;RECORD NUMBER COUNTER
EXTENT	DS	2	;EXTENT OF COPY BUFFER
FINISH	DS	1	;LAST BUFFER FLAG
SDMSG	DB	LF,'INSERT SOURCE DISK, <CR> TO CONTINUE'
	DB	CR,LF,EOM
DDMSG	DB	'INSERT COMP DISK, <CR> TO CONTINUE'
	DB	CR,LF,EOM
OPMSG	DB	LF,'FILE NOT FOUND',CR,LF,EOM
REMSG	DB	'READ ERROR ON FILE',CR,LF,EOM
COMPMSG	DB	'COMPARE COMPLETE - FILES IDENTICAL'
	DB	CR,LF,EOM
FSMSG	DB	'COMP FILE LONGER THAN SOURCE',CR,LF,EOM
FCMSG	DB	'COMP FILE SHORTER THAN SOURCE',CR,LF,EOM
HDGMSG	DB	LF,CR,'  RECORD  BYTE  SOURCE FILE'
	DB	'  COMP FILE',LF,CR,'    NO'
	DB	'    NO    HEX  ASCII   HEX  ASCII'
	DB	CR,LF,CR,LF,EOM
SPCMSG	DB	'    ',EOM
NASCMSG	DB	'???',EOM
CRLFMSG	DB	CR,LF,EOM
	DS	20H	;MINIMUM STACK SPACE
	;SET START OF BUFFER TO MULTIPLE OF SECTOR SIZE
	ORG	(($ + 7FH) / 80H) * 80H
STACK	EQU	$	;GROWS DOWN
BUFFER	EQU	$	;FILLS REST OF MEMORY TO CBASE
	END
