;COMPASC.ASM
;MOD OF COMPARE.ASM FOR ASCII 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
;02/11/82 MOD TO COMPASC BY RUSS BAKKE
;
	MACLIB	SEQIO
BSIZE	EQU	1024	;DISK BUFFER SIZE (TIMES 2)
	ORG	100H
;
;MACRO DEFS
;TYPE SINGLE CHAR OR CHAR IN A
TYPE	MACRO	?C
	IF	NOT NUL ?C
	MVI	A,?C
	ENDIF
	PUSH	B
	PUSH	D
	PUSH	H
	PUT	CON
	POP	H
	POP	D
	POP	B
	ENDM
;
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
	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
	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
;
;COMPASC.ASM - COMPARES 2 ASCII FILES
;
;COMMAND FORMAT: COMPASC NAME1 NAME2
;	IF NAME2 = NAME1 BUT IS ON B DISK,
;	JUST TYPE: COMPASC NAME1 B:
;
	LXI	SP,STACK	;INIT STACK
;
	PRINT	<'COMPASC.COM 02/11/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
;READ 8K INTO SECOND BUFFER
	GETF	BUF2ST,OK2,GETFILE2,EOF2FG,8192
;
;NOW START COMPARE
	LXI	H,BUF1ST
	LXI	D,BUF2ST
COMP	LDAX	D
	CMP	M
	JNZ	DIFFER
	CPI	CR
	CZ	EOL
	CPI	EOF
	JZ	EOFFND
	INX	H
	INX	D
	CALL	CKEOB1
	CZ	EOBUF1
	CALL	CKEOB2
	CZ	EOBUF2
	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 EOL+1, STEP (STOP AT EOF)
DIFF2	MVI	B,CR
	MVI	C,EOF
;ARE WE AT START OF LINE?
	DCX	H
	MOV	A,M
	INX	H
	CMP	B
	JZ	DIFF3	;YES, FORGET IT
;MOVE TO START OF NEXT LINE (EOL+1)
	CALL	GOSOL
	XCHG
	CALL	GOSOL
	XCHG
;
;NOW SEE IF WE ARE AT EOF IN EITHER FILE
DIFF3	MOV	A,M
	CMP	C
	JZ	DIFEOF
	LDAX	D
	CMP	C
	JZ	DIFEOF
;
;NOW FIND EXTEND OF DIFFERENCE.
;COMPARE CURRENT LINE IN FILE 1 TO
;NEXT 8 IN FILE 2.
;HL POINTS TO CURRENT LINE IN FILE 1,
;DE IN FILE 2
	MVI	C,EOF
	SHLD	CURR1	;SAVE CURRENT LINE
	XCHG
	SHLD	CURR2
	XCHG
	MVI	B,8	;8 LINES
DIFF4	LHLD	CURR1
	CALL	CKLINE
	PUSH	PSW
	CMP	C	;EOF?
	JZ	DIFEOF
	POP	PSW
	JZ	MATCH	;MATCH FOUND
	DCR	B
	JNZ	DIFF4
;
;NOW COMPARE CURRENT LINE IN FILE 2 TO
;NEXT 8 IN FILE 1
	MVI	B,8
	LHLD	CURR1
DIFF5	XCHG
	LHLD	CURR2
	XCHG
	CALL	CKLINE
	PUSH	PSW
	CMP	C	;EOF?
	JZ	DIFEOF
	POP	PSW
	JZ	MATCH
	DCR	B
	JNZ	DIFF5
;
;STILL NO MATCH FOUND.  PRINT 8 LINES
;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 LINES)
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	OK1
	CALL	PRBUF
	PRINT	<'*** FILE 2:',0DH,0AH>
	LHLD	OK2
	CALL	PRBUF
	JMP	EXIT
;
;PRBUF--PRINT BUFFER (AT HL) FOR 9 LINES OR EOF
PRBUF	MVI	B,9
PRBUF1	CALL	PRLINE	;PRINT LINE
	CPI	EOF	;AT EOF?
	JZ	PREOF
	DCR	B	;COUNT LINE
	JNZ	PRBUF1
	RET
;
;PREOF--AT EOF IN PRINT
PREOF	PRINT	<'*EOF',0DH,0AH>
	RET
;
;PRLINE--PRINT LINE (RET EOF IN A IF EOF)
PRLINE	MOV	A,M	;GET CHAR
	CPI	EOF
	RZ
	TYPE
	INX	H
	CPI	CR
	JNZ	PRLINE
	RET
;
;MATCH:  HAVE A MATCHED LINE.  HL & DE POINT
;TO START OF FOLLOWING LINE.
;PRINT FROM OK1 & OK2 TO END OF DIFF.
;UPDATE OK1 & OK2 & RETURN TO COMPARE.
MATCH	PUSH	H
	PUSH	D
;FIRST, MOVE HL & DE BACK TO START OF PREV. LINE
	DCX	H	;MOVE OFF THE C/R
	DCX	H
	DCX	D
	DCX	D
	CALL	RETSOL
	XCHG
	CALL	RETSOL
	SHLD	CURR2	;TEMP STORAGE
	XCHG
	SHLD	CURR1
;
;PRINT THE BUFFERS
	PUSH	H
	LDA	ERFLG
	ORA	A	;TEST ERROR FLAG
	JNZ	MAT1A
	INR	A	;SET IT
	STA	ERFLG
	PRINT	<'FILES UNEQUAL',0DH,0AH>
MAT1A	PRINT	<'****** FILE 1:',0DH,0AH>
	POP	D
;DE POINTS TO END OF BUFF1 TO BE PRINTED
	LHLD	OK1
MAT2	CALL	PRTOLM
MAT3	PRINT	<'*** FILE 2:',0DH,0AH>
	LHLD	CURR2	;NOW BUFF 2
	XCHG
	LHLD	OK2
MAT4	CALL	PRTOLM
;
;NOW UPDATE OK1, OK2, POINTERS
MAT5	LHLD	CURR1
	INX	H	;INC TO EOL+1
	SHLD	OK1
	LHLD	CURR2
	INX	H
	SHLD	OK2
	POP	D
	POP	H
	JMP	COMP	;RETURN TO COMPARE LOOP
;
;PRTOLM--PRINT FROM HL TO LIMIT IN DE
PRTOLM	CALL	PRLINE
	CALL	CMPHD	;COMPARE HL TO DE
	RZ		;DONE
	JNC	PRTOLM	;NOT DONE
	RET
;
;EOL--MOVE POINTERS TO "LAST OK LINES"
EOL	PUSH	H
	PUSH	D
	MVI	B,CR
	CALL	RETSOL	;BACK UP TO PREVIOUS LINE
	INX	H	;STEP TO EOL+1
	SHLD	OK1	;SAVE IT
	XCHG
	CALL	RETSOL
	INX	H
	SHLD	OK2
	POP	D
	POP	H
	RET
;
;EOBUF1-END OF BUFFER 1
;COPY FROM "LAST OK LINE" POINTER THRU END
;OF BUFFER, TO START OF BUFFER;
;REFILL REST OF BUFFER
;KEEP POINTER TO CURRENT CHAR (NOW AT EOBUF)
EOBUF1	REFILL	BUF1ST,OK1,CKEOB1,CURR1
;
;NOW FILL BUFFER
	XCHG
	GETF	,,GETFILE1,EOF1FG,
;
;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,
	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
;
;CKEOB2--SEE IF DE IS AT END OF BUFF2
CKEOB2	XCHG
	CKEOB	BUF2EN
	XCHG
	RET
;
;CKEOB2H--SEE IF HL IS AT END OF BUFF2
CKEOB2H	CKEOB	BUF2EN
	RET
;
;CKLINE--COMPARE LINE AT HL (BUFF1)
;TO LINE AT DE (BUFF2).  C=EOF
;IF EOF, RET EOF IN A; ELSE RET Z IF IDENTICAL,
;ELSE NZ
;STOPS AT EOL (& LEAVES DE, HL POINTING TO EOL+1)
CKLINE	LDAX	D
	CMP	M
	JNZ	LINDIF
	CPI	CR
	JZ	LINDON
	CMP	C	;EOF?
	RZ		;RET WITH EOF IN A
	MOV	A,M
	CMP	C
	RZ		;RET WITH EOF IN A
	INX	H
	INX	D
	JMP	CKLINE
;
;LINDON--INC POINTERS & EXIT
LINDON	INX	H
	INX	D
	RET		;NOTE THAT Z FLAG IS SET
;
;LINDIF--DIFFERENCE IN LINES.
;STEP HL & DE TO NEXT LINES; RET NZ.
;IF EOF, RET EOF IN A
LINDIF	INX	H
	MOV	A,M
	CMP	C	;EOF?
	RZ
	CPI	CR
	JNZ	LINDIF
LIND1	INX	D
	LDAX	D
	CMP	C	;EOF?
	RZ
	CPI	CR
	JNZ	LIND1
;STEP TO EOL+1 BEFORE RET
	INX	D
	INX	H
	ORI	1	;CLEAR Z FLAG
	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
;
;RETSOL--RET HL TO START OF LINE
RETSOL	MVI	A,CR
RETS1	DCX	H
	CMP	M
	JNZ	RETS1
	RET
;
;GOSOL--INC HL TO START OF NEXT LINE
;B=CR, C=EOF
GOSOL	MOV	A,M
	CMP	C
	RZ
	CMP	B
	INX	H
	JNZ	GOSOL
	RET
;
;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
EOF1FG	DB	0	;EOF FLAGS
EOF2FG	DB	0
BUF1ST	DS	8192
BUF1EN
BUF2ST	DS	8192
BUF2EN
BUFFERS	EQU	$
MEMSIZE	EQU	BUFFERS+@NXTB
	END
