; THIS PROGRAM COMPARES THE CONTENTS OF TWO FILES, BYTE BY BYTE ; ; USAGE: COMP -n FILE1 FILE2 ; -n is optional, limits output to n lines ; ; BY JON DART, DEPT. OF ANTHROPOLGY, UCSD C-001, LA JOLLA, CA 92093 ; ; VERSION 1.5: 15-MAR-85 ; VERSION 1.4: 19-JAN-85 ; VERSION 1.3: 15-JAN-85 ; VERSION 1.2: 03-JAN-85 ; VERSION 1.1: 12-JUN-84 ; MODIFIED FROM HDOS FOR CP/M: 06-APR-84 ; CP/M SYSTEM DEFINITIONS: BOOT EQU 0 BDOS EQU 0005H DEFFCB EQU 005CH DEFBUF EQU 0080H FCBSIZ EQU 36 SECSIZ EQU 128 R0 EQU 33 R2 EQU 35 LSTOUT EQU 5 DCIO EQU 6 CONIN EQU 1 CONOUT EQU 2 PRTSTR EQU 09H CONSTAT EQU 0BH VERS EQU 0CH SYSRES EQU 0DH SELDSK EQU 0EH FOPEN EQU 0FH FCLOSE EQU 10H SFF EQU 11H SFN EQU 12H FDELET EQU 13H FMAKE EQU 16H RCD EQU 19H SETDMA EQU 1AH GROV EQU 1DH SFA EQU 1EH GADP EQU 1FH USRCODE EQU 20H RDRAND EQU 21H WRRAND EQU 22H CFS EQU 23H ; ASCII CHARACTERS: CTRL$C EQU 3 LF EQU 0AH TAB EQU 09H CR EQU 0DH SPACE EQU 20H ORG 100H COMP EQU $ LXI H,0 DAD SP SHLD OLDSTK ;SAVE OLD STACK POINTER LXI SP,STACK LXI D,SIGNON MVI C,PRTSTR CALL BDOS CALL CRLF MVI C,VERS CALL BDOS MOV A,L CPI 20H JNC VERSOK ;IF NOT CP/M 2.2 LXI D,MSG0 MVI C,PRTSTR CALL BDOS JMP EXIT2 VERSOK: LXI H,FCB1 MVI B,FCBSIZ CALL ZERO ;ZERO FCB1 LXI H,FCB2 MVI B,FCBSIZ CALL ZERO ;AND FCB2 LXI H,DEFBUF ;GET BYTE COUNT FOR COMMAND LINE MOV A,M ANA A JZ NONAME ;IF NO NAME PUSH H MOV E,M MVI D,0 DAD D INX H MVI M,0 ;PUT 0 BYTE AT END OF COMMAND LINE POP H INX H CALL SKIPS ;SKIP SPACES JC NONAME ;IF END OF LINE CPI '-' JNZ NONUM ;IF NO NUMBER SPECIFIED INX H MVI C,0 PUSH H CD: MOV A,M ;HAVE NUMBER, COUNT NUMBER OF DIGITS CPI '0' JC NODGT CPI '9'+1 JNC NODGT INX H INR C JMP CD NODGT: SHLD NUMEND ;SAVE ADDRESS AFTER NUMBER POP H CALL DTOBIN ;CONVERT NUMBER TO BINARY JC NONAME ;IF ERROR XCHG INX H SHLD NUMLIN ;STORE AS # LINES LHLD NUMEND ;POINT TO 1 PAST NUMBER CALL SKIPS NONUM: LXI D,FCB1 CALL PACK ;MOVE NAME INTO FCB CALL SKIPS ;SKIP SPACES JC NONAME LXI D,FCB2 CALL PACK ;MOVE 2ND NAME INTO FCB JMP NAMEOK NONAME: LXI D,MSG1 MVI C,PRTSTR CALL BDOS JMP EXIT2 NAMEOK: LXI D,FCB1 MVI C,FOPEN PUSH D CALL BDOS ;TRY TO OPEN 1ST FILE POP D CPI 0FFH JZ BADOPN ;IF CAN'T OPEN LXI D,FCB2 MVI C,FOPEN PUSH D CALL BDOS ;TRY TO OPEN 2ND FILE POP D CPI 0FFH JNZ OPENOK ;IF CAN'T OPEN BADOPN: XCHG LXI D,FILNAM CALL FCOPY ;COPY FILE NAME INTO MESSAGE LXI D,MSG2 MVI C,PRTSTR CALL BDOS ;PRINT MESSAGE JMP EXIT SKIPS1: INX H SKIPS: MOV A,M ANA A STC RZ CPI SPACE JZ SKIPS1 CPI TAB JZ SKIPS1 ANA A RET ; PACK - TRANSLATE FILE NAME ON COMMAND LINE INTO FCB FORMAT ; ENTRY: (HL) POINTS TO FILE NAME ; (DE) POINTS TO FCB ; PACK: INX H MOV A,M CPI ':' DCX H JZ HAVED ;IF DRIVE SPECIFIED XRA A STAX D ;ELSE PUT 0 IN 1ST BYTE JMP PACK2 HAVED: MOV A,M SUI 'A'-1 STAX D INX H INX H PACK2: INX D PUSH H PUSH D XCHG MVI B,11 MVI A,SPACE CALL FILL ;FILL NAME FIELD WITH SPACES POP D POP H MVI C,8 PACK3: MOV A,M ;COPY NAME ANA A RZ CPI SPACE RZ INX H CPI '.' JZ PACK4 STAX D INX D DCR C JNZ PACK3 MOV A,M ;15-MAR-85 ANA A ;15-MAR-85 RZ ;15-MAR-85 INX H ;FIXES BUG ;15-MAR-85 JMP PACK5 PACK4: XCHG MOV B,C MVI A,SPACE CALL FILL XCHG PACK5: MVI C,3 ;COPY EXTENSION PACK6: MOV A,M ANA A RZ CPI SPACE RZ STAX D INX H INX D DCR C JNZ PACK6 RET ZERO: XRA A FILL: MOV M,A INX H DCR B JNZ FILL RET OPENOK EQU $ LHLD OLDSTK ;GET START OF CCP MOV E,M INX H MOV D,M XCHG LXI D,-10 ;SUBTRACT SLOP FACTOR DAD D SHLD TOPMEM ;SAVE ADDRESS LXI H,ENDDATA+1 ;PUT 1ST BUFFER SHLD BUF1 ;DIRECTLY ABOVE PROGRAM. XCHG LHLD TOPMEM CALL SUBHLDE ;SUBTRACT FROM TOP OF MEMORY DCR H ;-1 FOR SAFETY MOV A,H ANI 0FEH ;MAKE EVEN STA BUFSIZ ;STORE # CP/M SECTORS IN EACH BUFFER RRC ;DIVIDE BY 2 MOV H,A MVI L,0 XCHG LHLD BUF1 DAD D ;COMPUTE ADDRESS OF 2ND FILE BUFFER SHLD BUF2 ;SAVE IT ; HAVE OPENED BOTH FILES, NOW DO COMPARISON: LXI H,0 SHLD BLKNUM SHLD SEC1 SHLD SEC2 ;ZERO SECTOR COUNTS XRA A STA EOF1 ;CLEAR END OF FILE FLAGS STA EOF2 STA DIFF ;AND DIFFERENCE FLAG CALL CRLF ;WRITE CR/LF RDLOOP: LDA EOF1 LXI H,EOF2 ORA M ;IF END OF FILE ON EITHER CHANNEL, JNZ DONE ;DONE CALL READ1 ;READ 1ST FILE INTO BUFFER CALL READ2 ;READ 2ND FILE INTO BUFFER COMPARE: LHLD BUF2 XCHG ;(DE) POINTS TO 2ND BUFFER LHLD BUF1 ;(HL) POINTS TO 1ST BUFFER CMPLUP: PUSH H LXI H,SZTOCMP ;GET SECTOR COUNT TO COMPARE MOV A,M DCR M ;COUNT <-- COUNT -1 ANA A POP H JZ RDLOOP ;IF DONE W. BUFFERS, SEE IF MORE TO READ CALL CMPSEC ;COMPARE A SECTOR (128 BYTES) PUSH H LHLD BLKNUM INX H ;BUMP BLOCK COUNT SHLD BLKNUM POP H JMP CMPLUP ;LOOP ; READ1 - READ 1ST FILE INTO BUFFER ; ; ENTRY: NONE ; ; EXIT: 'C'=1 IF ERROR ; READ1 EQU $ LHLD BUF1 XCHG ;BUFFER ADDRESS IN (DE) LXI B,0 ;(BC) = COUNT OF SECTORS READ READ11: PUSH D PUSH B MVI C,SETDMA CALL BDOS ;SET DMA ADDRESS LHLD SEC1 SHLD FCB1+R0 ;PUT SECTOR COUNT IN FCB XRA A STA FCB1+R2 ;ZERO R2 LXI D,FCB1 MVI C,RDRAND CALL BDOS ;READ A SECTOR ANA A POP B POP D JNZ READ12 ;QUIT IF END OF FILE INX B ;BUMP # SECTORS READ XCHG LXI D,SECSIZ DAD D ;UPDATE BUFFER ADDRESS XCHG LHLD SEC1 INX H ;UPDATE BLOCK COUNT SHLD SEC1 MOV A,C ;GET # SECTORS READ LXI H,BUFSIZ CMP M ;COMPARE W. BUFFER SIZE JC READ11 ;LOOP TILL BUFFER FULL JMP READ13 READ12: MVI A,0FFH STA EOF1 ;SET EOF FLAG READ13: MOV A,C ;GET # SECTORS READ STA SZTOCMP ;STORE AS # SECTORS TO COMPARE READ14: ANA A ;CLEAR CARRY RET ; READ2 - READ 2ND FILE INTO BUFFER ; ; ENTRY: NONE ; ; EXIT: 'C'=1 IF ERROR ; READ2 EQU $ LHLD BUF2 XCHG ;BUFFER ADDRESS IN (DE) LXI B,0 ;(BC) = COUNT OF SECTORS READ READ21: PUSH D PUSH B MVI C,SETDMA CALL BDOS ;SET DMA ADDRESS LHLD SEC2 SHLD FCB2+R0 ;PUT SECTOR COUNT IN FCB XRA A STA FCB2+R2 ;ZERO R2 LXI D,FCB2 MVI C,RDRAND CALL BDOS ;READ A SECTOR ANA A POP B POP D JNZ READ22 ;QUIT IF END OF FILE INX B ;BUMP # SECTORS READ XCHG LXI D,SECSIZ DAD D ;UPDATE BUFFER ADDRESS XCHG LHLD SEC2 INX H ;UPDATE SECTOR COUNT SHLD SEC2 MOV A,C ;GET # SECTORS READ LXI H,BUFSIZ CMP M ;COMPARE W. BUFFER SIZE JC READ21 ;LOOP TILL BUFFER FULL RET READ22: MVI A,0FFH ;COME HERE IF END OF FILE STA EOF2 ;SET EOF FLAG MOV A,C ;GET # SECTORS READ LXI H,SZTOCMP CMP M RNC ;IF MORE THAN 1ST FILE MOV M,A ;SET AMT. TO COMPARE = SIZE OF SMALLER FILE ANA A RET ; COMPARE 1 SECTOR (128 BYTES): ; ; ENTRY: (DE), (HL) = ADDRESSES TO COMPARE ; ; EXIT: (DE), (HL) POINT TO START OF NEXT SECTORS ; CMPSEC: MVI C,SECSIZ ;(C) = BYTES TO COMPARE XRA A STA CHGFLG ;CLEAR CHANGE FLAG CSECT: LDAX D ;COMPARE 2 BUFFERS CMP M CNZ NOTEQU INX H INX D DCR C JNZ CSECT RET NOTEQU: PUSH H ;FOUND A DIFFERENCE, TELL ABOUT IT PUSH D PUSH B LHLD NUMLIN DCX H SHLD NUMLIN MOV A,L ORA H JZ EXIT ;IF PRINTED MAX. LINES LXI D,MSG3 MVI C,PRTSTR CALL BDOS LHLD BLKNUM XRA A CALL DECOUT ;SHOW SECTOR # LXI D,MSG4 MVI C,PRTSTR CALL BDOS POP B PUSH B ;GET COUNT REMAINING MVI A,SECSIZ SUB C ;SUBTRACT FROM SECTOR SIZE PUSH PSW ;SAVE OFFEST FR. START OF SECTOR MOV L,A MVI H,0 ;PUT IN (HL) MVI A,SPACE CALL DECOUT ;SHOW IT MVI A,SPACE CALL COUT MVI A,'(' CALL COUT LDA BLKNUM ANA A RAR ;DIVIDE SECTOR COUNT BY 2 TO GET PAGE MOV H,A ;SAVE IT MVI B,0 JNC EVEN ;IF EVEN PAGE MVI B,80H EVEN: POP PSW ADD B ;IF ODD PAGE, ADD 80H TO LOW BYTE MOV L,A CALL HEXOUT ;SHOW HEX OFFSET FROM START OF FILE LXI D,MSG5 MVI C,PRTSTR CALL BDOS MVI A,0FFH STA CHGFLG STA DIFF POP B POP D POP H RET ; COME HERE WHEN DONE: DONE: LHLD SEC1 XCHG LHLD SEC2 ;FILES ARE SAME SIZE? CALL COMPRP PUSH PSW ;SAVE RESULT OF COMPARISON JNZ NOTIDEN ;IF SIZES NOT IDENTICAL LDA DIFF ANA A ;DIFFERENCES FOUND? - JNZ NOTIDEN ;- YES, FILES NOT IDENTICAL POP PSW ;- NO, CLEAR STACK LXI D,MSG6 ;GIVE "IDENTICAL" MESSAGE MVI C,PRTSTR CALL BDOS JMP EXIT ; COME HERE IF FILES NOT = NOTIDEN EQU $ POP PSW LXI H,FCB1 JC EOFON2 ;IF EOF ON FILE 2 BEFORE FILE 1 LXI H,FCB2 EOFON2: LXI D,EOFNAM ;SHOW FILE NAME CALL FCOPY LXI D,MSG7 MVI C,PRTSTR CALL BDOS EXIT: LXI D,FCB1 ;CLOSE FILES MVI C,FCLOSE CALL BDOS LXI D,FCB2 MVI C,FCLOSE CALL BDOS EXIT2: LHLD OLDSTK SPHL RET ;RETURN TO CCP FCOPY: MOV A,M INX H ANA A JZ NODRV ADI 'A'-1 STAX D INX D MVI A,':' STAX D INX D NODRV: MVI B,11 FCOPY1: MOV A,M CPI SPACE JZ NOCOPY STAX D INX D NOCOPY: INX H DCR B RZ MOV A,B CPI 3 JNZ FCOPY1 MVI A,'.' STAX D INX D JMP FCOPY1 ; UTILITY SUBROUTINES: ; CONVERT A 16-BIT UNSIGNED BINARY NUMBER TO DECIMAL AND OUTPUT ; IT TO THE CONSOLE. LEADING ZEROS ARE SUPPRESSED. ; ; ENTRY: (HL) = NUMBER ; (A) = CHAR. TO PRINT INSTEAD OF LEADING 0 ; ; EXIT: NONE ; ; USES: ALL 8080 REGISTERS ; ZEROCHR: DS 1 DECOUT: STA ZEROCHR MVI B,0 LXI D,-10000 CALL PRTDGT LXI D,-1000 CALL PRTDGT LXI D,-100 CALL PRTDGT LXI D,-10 CALL PRTDGT MOV A,L ADI 60Q JMP COUT PRTDGT: MVI C,0FFH PUSH H PRT1: INR C INX SP INX SP PUSH H DAD D JC PRT1 POP H MOV A,C ;IF DIGIT IS A 0 ORA B ;AND NO NON-ZERO DIGIT HAS BEEN PRINTED, LDA ZEROCHR ;WRITE SPECIAL CHAR. JZ COUT MOV A,C ;ELSE WRITE A DIGIT ADI 60Q MOV B,A JMP COUT ; DTOBIN - CONVERT A 5-DIGIT (MAX.) UNSIGNED DECIMAL NUMBER INTO A ; BINARY VALUE. ; ; ENTRY: (C) = NO. OF DIGITS ; (HL) POINTS TO CHAR. STRING (MSD FIRST) ; ; EXIT: (DE) = CONVERTED NUMBER ; 'C' FLAG SET IF OVERFLOW (>64384) OR ERROR ; ; USES: ALL 8080 REGS. ; DGTPTR: DS 2 DTOBIN: XRA A MOV D,A MOV E,A ;CLEAR (DE) - SERVES AS ACCUMULATOR CMP C ;MAKE SURE (C) NOT ZERO RZ PUSH H DTOB: SHLD DGTPTR ;SAVE (HL) AS DIGIT POINTER MOV A,M ;GET DIGIT POP H CALL VALDGT ;CHECK FOR VALID DECIMAL DIGIT RC ;RETURN WITH ERROR IF NOT ANI 0FH ;CONVERT ASCII DIGIT TO BINARY XCHG ;SAVE SUM IN (HL) MOV E,A ;MOVE DIGIT TO (DE) MVI D,0 MOV B,C DCR B ;PUT COUNT IN (B) = DIGIT COUNT -1 JZ DTOB$1 ;IF =0, SKIP X10 ROUTINE DEX10: PUSH H CALL MU10 ;MULTIPLY (DE) BY 10 XCHG POP H RC ;(B) TIMES - RETURN ON OVERFLOW DCR B JNZ DEX10 DTOB$1: DAD D ;ADD PRODUCT TO RESULT RC ;RETURN ON OVERFLOW XCHG ;SAVE NEW SUM DCR C RZ ;FINISHED IF COUNT=0 PUSH H LHLD DGTPTR INX H ;ELSE BUMP DIGIT POINTER JMP DTOB ;& CONVERT NEXT DIGIT MU10: XCHG DAD H RC MOV D,H MOV E,L DAD H RC DAD H RC DAD D RET ; SUBROUTINE - RETURNS WITH 'C' FLAG SET IF CHAR. IN (A) IS NOT ; IN THE RANGE 0-9 VALDGT: CPI '0' RC CPI ':' CMC RET ; HEXOUT - SHOW 16-BIT WORD IN HEX ; ENTRY: (HL) = WORD HEXOUT: MVI B,0 MOV A,H RRC RRC RRC RRC CALL HEXDGT MOV A,H CALL HEXDGT MOV A,L RRC RRC RRC RRC CALL HEXDGT MOV A,L ANI 0FH JMP SHOWHX ; HEXDGT - WRITE NIBBLE IN (A) AS HEX DIGIT HEXDGT: ANI 0FH JNZ SHOWHX PUSH PSW MOV A,B ANA A JZ NOSHOW POP PSW SHOWHX: INR B CPI 10 JNC LETTER ADI '0' JMP COUT LETTER: ADI 'A'-10 JMP COUT NOSHOW: POP PSW RET ; CHARACTER OUTPUT ; ENTRY: (A) = CHAR. TO PRINT COUT: DS 0 PUSH H PUSH D PUSH B PUSH PSW ANI 07FH MOV E,A MVI C,CONOUT CNZ BDOS POP PSW POP B POP D POP H RET ; WRITE CR + LF CRLF: MVI A,CR CALL COUT MVI A,LF JMP COUT ; COMPRP = COMPARE REGISTER PAIR ; ; ENTRY: (HL), (DE) SET ; ; EXIT: 'Z'=1 IF (HL)=(DE) ; 'C'=1 IF (HL)>(DE) ; COMPRP: MOV A,D CMP H RNZ MOV A,E CMP L RET ; SUBHLDE = SUBTRACT (DE) FROM (HL) ; ; ENTRY: (HL), (DE) SET ; ; EXIT: (HL) = (HL) - (DE) ; 'C' AND 'Z' FLAGS REFLECT RESULTS OF SUBTRACTION ; ; USES: F,H,L ONLY ; SUBHLDE: DS 0 PUSH B MOV B,A ;SAVE (A) XCHG CALL COMPRP ;SET FLAGS XCHG MOV A,B ;RESTORE (A) POP B PUSH PSW ;SAVE (A) AND FLAGS MOV A,L SUB E MOV L,A ;DO SUBTRACTION MOV A,H SBB D MOV H,A POP PSW ;RESTORE (A) AND FLAGS RET ; MEMORY DEFINITIONS: ; FCB1: DS FCBSIZ FCB2: DS FCBSIZ OLDSTK: DS 2 ;STACK POINTER ON ENTRY BLKNUM: DS 2 ;BLOCK NUMBER CHGFLG: DS 1 ;FLAG, <>0 IF DIFFERENCE IN SECTOR DIFF: DS 1 ;FLAG, <>0 IF ANY DIFFERENCE FOUND TOPMEM: DS 2 ;TOP OF USER MEMORY BUFSIZ: DS 2 ;SIZE OF FILE BUFFERS BUF1: DS 2 ;ADDRESS OF 1ST FILE BUFFER BUF2: DS 2 ;ADDRESS OF 2ND FILE BUFFER EOF1: DS 1 ;FLAG, <>0 WHEN END OF FILE ON FILE 1 EOF2: DS 1 ;FLAG, <>0 WHEN END OF FILE ON FILE 2 SEC1: DS 2 ;NO. OF SECTORS READ FROM FILE 1 SEC2: DS 2 ;" " " " " " 2 SZTOCMP: DS 1 ;# OF BLOCKS TO COMPARE NUMEND: DS 2 ;END OF NUMBER DS 40 ;STACK AREA STACK: DS 0 ;TOP OF STACK NUMLIN: DW 20 ;NUMBER OF LINES TO LIST SIGNON: DB 'COMP V. 1.5 BY JON DART (15-MAR-85)$' MSG0: DB CR,LF,'CP/M 2.X REQUIRED.',CR,LF,'$' MSG1: DB CR,LF,'USAGE: COMP -n filename1 filename2',CR,LF DB SPACE,SPACE,SPACE,SPACE,SPACE,SPACE,SPACE DB '-n is optional, limits output to n lines (default 20)','$' MSG2: DB CR,LF,'CAN''T OPEN: ' FILNAM: DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,CR,LF,'$' MSG3: DB 'FILES DIFFER AT SECTOR $' MSG4: DB ', BYTE $' MSG5: DB 'H).',CR,LF,'$' MSG6: DB 'FILES ARE IDENTICAL.',CR,LF,'$' MSG7: DB CR,LF,'END OF FILE ON ' EOFNAM: DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,CR,LF,'$' ENDDATA EQU $ END