; ;01/16/88 ADDED HELP MESSAGE, USER AREA SUPPORT. TAH ; FIX EXIT BUG. ; FOR HELP TYPE: COMPARE ; OR ; COMPARE $? ; ;REQUIRES MAC.COM AND SEQIOU.LIB FOR ASSEMBLY ; SEQIOU.LIB IS A REVISED VERSION OF SEQIO.LIB FROM CPMUG VOL 29 ; WITH USER AREA SUPPORT ADDED TO THE "FILE" MACRO. ; ;11/??/77 ORIGINALLY WRITTEN BY WARD CHRISTENSEN ;12/31/77 ADD PICKUP OF SECOND FILENAME IF BLANK ;01/08/78 ADD SEQIO MACLIB TO READ BIG BLOCKS ; BSIZE EQU 4096 ;DISK BUFFER SIZE (TIMES 2) LINES EQU 14 ;LINES TO PRINT BEFORE PAUSE CTRLC EQU 03 ;CONTROL C ; ORG 100H ; MACLIB SEQIOU ; ;COMPARE.ASM - COMPARES 2 FILES ; ;COMMAND FORMAT: COMPARE NAME1 NAME2 ; IF NAME2 = NAME1 BUT IS ON B DISK, ; JUST TYPE: COMPARE NAME1 B: ; ;INIT STACK ; POP H ;GET CP/M RET ADDR SHLD EXIT1+1 ;MODIFY RETURN ADDR LXI SP,STACK ;GET MY STACK ; CALL INLMSG DB 'COMPARE.COM v3',0DH,0AH,'$' LXI H,@TBUF MOV A,M ORA A JZ HELP ;IF EMPTY COMMAND LINE, GIVE HELP MOV E,A ;CHARACTER COUNT MVI D,00 ;CLEAR D DAD D ;HL POINTS TO END OF LINE INR E INIT: DCR E JZ HELP MOV A,M DCX H CPI ' ' ;SCAN BACKWARDS FOR FIRST SPACE JNZ INIT ;LOOP BACK IF NOT SPACE INX H INX H MOV A,M CPI '$' ;IS SPACE FOLLOWED BY $ ? JNZ INIT2 ;NO, OPTIONS NOT SPECIFIED. INX H ;YES, CHECK NEXT CHAR. MOV A,M CPI '?' ;NEED HELP MESSAGE JZ HELP CPI 'S' JNZ INIT2 STA SHOFLG ;SAVE S OPTION. INX H MOV A,M XCHG ;POINTER TO DE LXI H,0100H ;DEFAULT ORIGIN ADDRESS CALL VALHEX ;HEX ADDRESS GIVEN? JC INIT1 ;NO, USE DEFAULT VALUE LXI H,0 ;YES, CONVERT ASCII TO BINARY MVI B,0 ; ADRLUP: LDAX D INX D CALL VALHEX ;CHECK FOR VALID HEX CHARACTER JC INIT1 ;QUIT IF NOT. ADDNIB: DAD H ;*2 DAD H ;*4 DAD H ;*8 DAD H ;*16 TO SHIFT PARTIAL SUM MOV C,A DAD B ;ADD IN NEXT DIGIT JMP ADRLUP INIT1: SHLD ADDR ;SAVE S OPTION ADDRESS ; INIT2: CALL PCL ;PARSE COMMAND LINE ; ;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 1 BYTE AT A TIME ; COMP CALL READ1 MOV B,A ;SAVE CHAR PUSH B CALL READ2 POP B CMP B JZ FIXADDR ;IF THE SAME, CONTINUE ; ;FILES UNEQUAL ; MOV C,A ;SAVE FILE2 CHARACTER LDA SHOFLG CPI 'S' ;SHOW ALL DIFFERENCES? JNZ UNEQUAL ;NO, DISPLAY FILE BUFFER AND QUIT CALL SHOW ;YES, SHOW ADDRESS AND DATA... FIXADDR: LHLD ADDR INX H ;...UPDATE ADDRESS SHLD ADDR JMP COMP ;GO BACK FOR MORE. ; UNEQUAL CALL INLMSG DB 'FILES UNEQUAL AFTER ','$' PRBYTES LXI D,BYTES MVI C,@MSG CALL @BDOS CALL INLMSG DB 'LAST DATA READ FROM FILE 1:',0DH,0AH,'$' LHLD PRTPTR ; ;THE FOLLOWING DISPLAYS THE LAST CONTENTS OF THE FILE1 BUFFER ;IN A MANNER SIMILAR TO THE DDT "D" COMMAND (HEX DATA FOLLOWED ;BY ASCII EQUIVALENT) ; DISP MVI B,16 ;DISPLAY 16 LINES DISP0 MVI C,16 ;AT 16 CHAR PER LINE PUSH H DISP1 MOV A,M ;GET DATA BYTE INR L ;BUMP POINTER CALL HEXOUT ;DISPLAY AS HEX MVI A,' ' ;FOLLOW WITH A SPACE CALL TYPE DCR C JNZ DISP1 ;DO 16 TIMES POP H MVI C,16 DISP2 MOV A,M ;GET DATA AGAIN INR L CPI ' ' JC DOTOUT ;REPLACE NON-PRINTING CHAR. WITH DOT CPI 7FH JC NODOT DOTOUT MVI A,'.' NODOT CALL TYPE ;DISPLAY THE CHARACTER DCR C JNZ DISP2 ;LOOP FOR 16 COUNT PUSH H PUSH B CALL INLMSG ;START A NEW LINE DB 0DH,0AH,'$' POP B POP H DCR B JNZ DISP0 ;DISPLAY LAST 256 BYTES OF FILE1 JMP EXIT ;AND QUIT ; ;READ BYTE FROM FILE 1 ; READ1 GET FILE1 JZ EOF1 ;GOT EOF? LHLD PRTPTR MOV M,A INR L SHLD PRTPTR PUSH PSW ;SAVE CHAR LXI H,BYTES+5 READI MOV A,M ORI '0' ;IN CASE IT WAS BLANK INR A MOV M,A CPI '9'+1 ;TIME TO CARRY? JNZ READNC MVI M,'0' DCX H JMP READI READNC POP PSW RET ; ;EOF ON FILE 1 - SET FLAG, READ 2 ; EOF1 MVI A,'Y' STA EOFLG CALL READ2 CALL INLMSG DB 'EOF FILE 1, NOT FILE 2',0DH,0AH,'$' JMP UNEQUAL ; READ2 GET FILE2 RNZ ;NO EOF ; ;GOT EOF ON FILE 2, MUST HAVE GOTTEN IT ON FILE 1 ; EOF2 LDA EOFLG CPI 'Y' JZ AOK CALL INLMSG DB 'EOF FILE 2 BEFORE FILE 1',0DH,0AH,'$' JMP UNEQUAL ; ;A-OK - FILES MATCH ; AOK LDA ERRFLG ORA A JNZ EXIT CALL INLMSG DB 'FILES MATCH, LENGTH IS ','$' LXI D,BYTES MVI C,@MSG CALL @BDOS ;NOTE THE FOLLOWING DOES NOT RESTORE CP/M'S ;STACK POINTER, BUT THAT IS 'OK' BECAUSE THE ;FIRST INSTRUCTION IN CP/M IS A LXI SP EXIT MVI C,20H ;RESTORE USER NUMBER LDA DEFUSR MOV E,A CALL @BDOS EXIT1 JMP $-$ ;CP/M RET ADDR (MODIFIED) ; ERXIT POP D ;GET MESSAGE MVI C,@MSG CALL @BDOS JMP EXIT ; ;MOVE FROM (DE) TO (HL) LENGTH IN B MOVER LDAX D MOV M,A INX D INX H DCR B JNZ MOVER RET ; ;DISPLAY HEX ADDRESS AND FILE1, FILE2 DATA ; SHOW MVI A,0FFH STA ERRFLG ;SET FILE MISMATCH FLAG LHLD ADDR PUSH B CALL HLOUT ;DISPLAY HEX ADDRES MVI A,'-' CALL TYPE POP B PUSH B MOV A,B CALL HEXOUT ;FIRST DATA BYTE MVI A,' ' CALL TYPE POP B MOV A,C CALL HEXOUT ;SECOND DATA BYTE CALL INLMSG ;START NEW LINE. DB 0DH,0AH,'$' LDA LINCNT DCR A STA LINCNT RNZ MVI A,LINES STA LINCNT CALL INLMSG ;ALLOW TIME TO VIEW THE SCREEN DB '[More]','$' MVI C,1 CALL @BDOS ;WAIT FOR KEYPRESS ANI 5FH CPI CTRLC ;ABORT IF CTRL C JZ EXIT CALL INLMSG ;ELSE, SHOW MORE DB 0DH,0AH,'$' RET ; ;DISPLAY HL AS HEX ; HLOUT MOV A,H PUSH H CALL HEXOUT POP H MOV A,L ; ;DISPLAY ACC. AS HEX ; HEXOUT PUSH PSW RAR RAR RAR RAR CALL PRTNBL POP PSW PRTNBL ANI 0FH CPI 10 ;CONVERT TO ASCII JC SML ADI 7 SML ADI '0' JMP TYPE ; ;CONVERT ACC FROM ASCII TO HEX DIGIT, RETURN CARRY FLAG CLEAR ;IF VALID HEX DIGIT. ; VALHEX SUI '0' ;SUBTRACT ASCII ZERO OFFSET RC CPI 16+7 ;GREATER THAN "F" ? CMC ;ADJUST CARRY FLAG RC CPI 10 CMC ;ADJUST CARRY FLAG RNC SUI 7 ; A-F OFFSET RET ; ; OUTPUT IN-LINE MESSAGE TO CONSOLE INLMSG: XTHL ;SAVE H, GET TEXT LOCATION PUSH PSW MOV A,M INLML: CALL TYPE INX H MOV A,M CPI '$' JNZ INLML ;$ ENDS TEXT INX H POP PSW XTHL RET ;RETURN AFTER TEXT ; ;SEND CONTENTS OF ACC. TO CONSOLE ; TYPE PUSH B PUSH D PUSH H MOV E,A MVI C,2 CALL @BDOS POP H POP D POP B RET ; ;THE FOLLOWING ROUTINE ALLOWS FILES IN DIFFERENT USER AREAS ;TO BE COMPARED. ;SINCE THE CP/M CCP CANNOT DEAL WITH THE d/u: FORM OF DRIVE/USER ;SPECIFICATION WE MUST PROVIDE A BUILT-IN ROUTINE TO PARSE THE ;COMMAND LINE FILE NAMES AND BUILD THE DEFAULT FCB AT 5CH AND 6CH. ; PCL: MVI C,20H MVI E,0FFH CALL @BDOS ;GET CURRENT USER NUMBER STA DEFUSR ;AND SAVE ; LXI H,@TBUF+2 LXI D,@TFCB CALL SCAN MOV A,C ;GET USER FOR FILE 1 STA FILE1USR MOV A,B ;GET DRIVE FOR FILE 1 STA @TFCB MOV A,M CPI 00H ;COMMAND LINE TERMINATOR? JZ PCL1 ;IF YES, DONE. INX H ;SKIP SPACE LXI D,@TFCB+16 CALL SCAN MOV A,C ;GET USER FOR FILE 2 STA FILE2USR MOV A,B ;GET DRIVE FOR FILE 2 STA @TFCB+16 RET PCL1: LDA DEFUSR STA FILE2USR ;SET USER FOR FILE2 TO DEFAULT. RET ; ;SFNAME.MAC FROM SYSLIB 2.0 ;* ;* SCAN is a file name scanner. Pointing to the first character ;* of a file name specification of the form 'du:filename.typ', where ;* any part of this specification is optional, this routine ;* properly initializes the FN and FT (File Name and ;* File Type) fields if 'filename.typ' or any part thereof is present, ;* and returns the value of d and u if they are specified ;* ;* MAXDISK EQU 16 ; MAX NUMBER OF DISKS MAXUSER EQU 31 ; MAX USER NUMBER ;* ;* MAIN MODULE ;* ON ENTRY, DE PTS TO FCB TO BE FILLED AND HL PTS TO FIRST BYTE OF ;* TARGET STRING; FCB IS 36 BYTES LONG ;* ON EXIT, B=DISK NUMBER (1 FOR A, ETC) AND C=USER NUMBER ;* HL PTS TO TERMINATING CHAR ;* A=0 AND Z SET IF ERROR IN DISK OR USER NUMBERS, A=0FFH AND NZ ;* IF OK ;* SCAN: MVI A,00H ; SET DEFAULT DISK AND USER STA DISK LDA DEFUSR STA USER PUSH D PUSH H ; SAVE PTR COLON: ; SCAN FOR COLON IN STRING MOV A,M ; SCAN FOR COLON OR SPACE INX H ; PT TO NEXT CPI ':' ; COLON FOUND? JZ COLON1 CPI ',' ; COMMA FOUND? JZ GETF1 CPI ' '+1 ; DELIM? JC GETF1 JMP COLON ; CONTINUE IF NOT END OF LINE COLON1: POP H ; CLEAR STACK MOV A,M ; SAVE POSSIBLE DRIVE SPEC CPI 'A' ; DIGIT IF LESS THAN 'A' JC USERCK ; PROCESS USER NUMBER SUI 'A' ; CONVERT TO 0-15 CPI MAXDISK ; WITHIN BOUNDS? JC SVDISK ERREXIT: XRA A ; ERROR INDICATOR POP D ; RESTORE DE CALL ERXIT DB CR,LF,'COMMAND LINE SYNTAX ERROR','$' RET ; REDUNDANT ; LOG IN SPECIFIED DISK SVDISK: INR A ; ADJUST TO 1 FOR A STA DISK ; SAVE FLAG INX H ; PT TO NEXT CHAR ; CHECK FOR USER USERCK: MOV A,M ; GET POSSIBLE USER NUMBER CPI ':' ; NO USER NUMBER JZ GETFILE CPI '?' ; ALL USER NUMBERS? JNZ USERC1 JMP ERREXIT ; FATAL ERROR USERC1: XRA A ; ZERO USER NUMBER MOV B,A ; B=ACCUMULATOR FOR USER NUMBER USRLOOP: MOV A,M ; GET DIGIT INX H ; PT TO NEXT CPI ':' ; DONE? JZ USRDN SUI '0' ; CONVERT TO BINARY JC ERREXIT ; USER NUMBER ERROR? CPI 10 JNC ERREXIT MOV C,A ; NEXT DIGIT IN C MOV A,B ; OLD NUMBER IN A ADD A ; *2 ADD A ; *4 ADD B ; *5 ADD A ; *10 ADD C ; *10+NEW DIGIT MOV B,A ; RESULT IN B JMP USRLOOP USRDN: MOV A,B ; GET NEW USER NUMBER CPI MAXUSER+1 ; WITHIN RANGE? JNC ERREXIT STA USER ; SAVE IN FLAG JMP GETFILE ; EXTRACT FILE NAME GETF1: POP H ; GET PTR TO BYTE GETFILE: MOV A,M ; PTING TO COLON? CPI ':' JNZ GFILE1 INX H ; SKIP OVER COLON GFILE1: MOV A,M ; GET NEXT CHAR CPI ',' ; DELIM? JZ GFQUES CPI ' '+1 ; NOT A DELIMITER? JNC GFILE2 GFQUES: INX D ; FILL WITH ' ' MVI B,11 ; 11 BYTES MVI A,' ' GFFILL: STAX D ; PUT SPACE INX D ; PT TO NEXT DCR B ; COUNT DOWN JNZ GFFILL FNDONE: LDA DISK ; GET DISK NUMBER MOV B,A ; ... IN B LDA USER ; GET USER NUMBER MOV C,A ; ... IN C POP D ; RESTORE REGS MVI A,0FFH ; NO ERROR ORA A ; SET FLAGS RET ; GET FILE NAME FIELDS GFILE2: MVI B,8 ; AT MOST 8 BYTES FOR FN CALL SCANF ; SCAN AND FILL MVI B,3 ; AT MOST 3 BYTES FOR FT MOV A,M ; GET DELIMITER CPI '.' ; FN ENDING IN '.'? JNZ GFILE3 INX H ; PT TO CHAR AFTER '.' CALL SCANF ; SCAN AND FILL JMP FNDONE ; DONE ... RETURN ARGS GFILE3: CALL SCANF4 ; FILL WITH JMP FNDONE ; ; SCANNER ROUTINE ; SCANF: CALL DELCK ; CHECK FOR DELIMITER JZ SCANF4 ; FILL IF FOUND INX D ; PT TO NEXT BYTE IN FN CPI '*' ; ? FILL? JZ ERREXIT ;NO WILDCARDS ALLOWED CPI '?' JZ ERREXIT ;NO WILDCARDS ALLOWED SCANF1: STAX D ; PLACE CHAR INX H ; PT TO NEXT POSITION SCANF2: DCR B ; COUNT DOWN JNZ SCANF ; CONTINUE LOOP SCANF3: CALL DELCK ; "B" CHARS OR MORE - SKIP TO DELIMITER RZ INX H ; PT TO NEXT JMP SCANF3 SCANF4: INX D ; PT TO NEXT FN OR FT MVI A,' ' ; FILL STAX D DCR B ; COUNT DOWN JNZ SCANF4 RET ;* ;* BUFFERS ;* DISK: DS 1 ; DISK NUMBER USER: DS 1 ; USER NUMBER ; ; CHECK CHAR PTED TO BY HL FOR A DELIMITER ; RET WITH Z FLAG SET IF DELIMITER ; DELCK: MOV A,M ; GET CHAR ORA A ; 0=DELIM RZ CPI ' '+1 ; +1 JC DELCK1 ; OR LESS CPI '=' RZ CPI 5FH ; UNDERSCORE RZ CPI '.' RZ CPI ':' RZ CPI ';' RZ CPI ',' RZ CPI '<' RZ CPI '>' RET DELCK1: CMP M ; COMPARE WITH SELF FOR OK RET ; HELP LXI D,USAGE MVI C,9 CALL @BDOS JMP EXIT ; USAGE DB CR,LF DB 'Determines if two files are equal',CR,LF DB ' Usage:',CR,LF,CR,LF DB 'COMPARE [du:]UFN1.UFT [du:][UFN2.UFT] [' DB '$' OR 80H ;ALLOWS DOLLAR SIGN IN MESSAGE DB 'S[ADDR]]',CR,LF,CR,LF DB 'du are optional drive and user area for the files.',CR,LF DB 'UFN1.TYP is the first unambiguous file name.',CR,LF DB 'UFN2.TYP is the second unambiguous file name and',CR,LF DB 'will default to UFN1.TYP if only du2: is given.',CR,LF DB CR,LF DB 'The optional ', '$' OR 80H, 'S ' DB 'is primarily for .COM or similar files',CR,LF DB 'and will Show all addresses with data bytes that differ.' DB CR,LF DB 'ADDR is an optional HEX origin address (default = 0100)' DB CR,LF,CR,LF DB 'Example: COMPARE B:FOOBAR.COM C3:WOMBAT.OBJ ','$' OR 80H DB 'S7E00',CR,LF DB '$' ; EOFLG DB 'N' COL DB 0 BYTES DB ' BYTES',0DH,0AH,'$' PRTPTR DW BUFF ; DEFUSR DB 0 F1USER DB 0 F2USER DB 0 ; LINCNT DB LINES SHOFLG DB 0 ADDR DW 1 ERRFLG DB 0 DS 30 ;STACK STACK EQU $ ;ORG TO PAGE BECAUSE 'INR L' USED TO LOOP THRU IT ORG ($+255) AND 0FF00H ;TO PAGE BUFF EQU $ REPT 16 DB ' ' ENDM BUFFERS EQU $ MEMSIZE EQU BUFFERS+@NXTB END