; Binary compare file 1 and file 2. By C.B. Falconer. ; ; d>FDIFF [-o] [d[u]:]file1.typ [d[u]:][file2.typ] ; compares file1.typ to file2.typ ; (with full du addressing, across users, drives) ; the (optional) -options cause: ; n no page pauses ; number offset for 1st file byte ; (default 0, 0100h for .COM files) ; (number must be the last option) ; ; 1.1 86/12/02 Minor changes to use BUFFLIB 1.4, keep under 2k ; ; EX: d>FDIFF -n100 c3:fdiff.obj ; compares c3:fdiff.obj against current du:fdiff.obj, ; with initial address set to 0100h. ; ; SEE BUFFERS.DOC for linking instructions ; ver equ 11 ; boot equ 0 tfcb equ boot+05ch defdma equ boot+080h @cin equ 1 @csta equ 11 ; cr equ 0dh lf equ 0ah tab equ 9 stksize equ 128; includes b.ohead multi equ 1 nopause equ 2; flag word bits delta equ 080h; a difference found ; extrn .dos, b.ohead, .bfgetc extrn .bfropen, .pfnmdu, .xltusr extrn .skipblks, .nextch, .qnum extrn .couta, .tadzs, .tfnam, .t2hx, .t4hx, .crlf extrn .endata; End of data storage segment ; jmp begin; around patch area ; ; patchable constants lpp: db 20; lines per page before pause ; begin: lhld 6; set stack at top of memory mvi l,0 sphl ; " " ; allocate the largest possible buffer lxi d,-.endata-stksize dad d; form size of memory available ora a; split into two buffers mov a,h ! rar ! mov h,a mov a,l ! rar ! mov l,a push h; save buffer size ; " " ; mark end of command line, just in case. ; Done by most CCPs, but undocumented. CCPLUS is documented ; lxi h,defdma ; mov a,m; line length ; inx h ! add l ! mov l,a ; adc h ! sub l ! mov h,a ; mvi m,0; mark eol ; " " call clear; flags and counters ; " " ; check for a verify flag lxi d,defdma+1 call .skipblks cpi '-' jnz parse; no options call .nextch flgs1: call setup; some flag jc parse; not a valid flag, start over cpi ' ' jnz flgs1; check another jmp parse1; field terminated. ptr past options ; ; parse the file names parse: call clear; in case bad options altered lxi d,defdma+1; set command scanning pointer ; " " ; Entry when command line options found parse1: lxi h,fcbin call .pfnmdu; will parse an empty line into lda fcbin+1; a blank FCB. sui ' ' jz exit; no file specified, give help mov a,b; designated user call .xltusr; convert 0 into current, etc sta inuser; needed for chksame and show mov a,b; but bfropen needs original form pop b; get buffer size back push d; save input scan pointer lxi d,fcbin lxi h,.endata call .bfropen; open buffered file for read mvi a,1 jc exit; can't find it, abort lxi h,.endata+b.ohead dad b; now rounded down to 128 mult. shld @outbuff; allocate output buffer pop d; restore input scan pointer push h; @outbuff push b; save buffer size lxi h,fcbout push h call .pfnmdu mov a,b; designated user call .xltusr; convert to standard form sta outuser; save for future lda fcbout+1 cpi ' ' cz filejam; no 2nd file, copy file1 name mov a,b pop d; fcbout pop b; buffer size pop h; @outbuff call .bfropen; open buffered file for read mvi a,2 jc exit; can't find file2 call chksame; ensure not comparing against self call chkcom; to set base to 0100h for .COMs ; " " ; All files open, files different, and buffers assigned. ; Compare fcbin and fcbout in largest possible blocks diff: lxi h,address call incrm; keep track of address lxi h,.endata call .bfgetc jc donea mov b,a lhld @outbuff call .bfgetc jc doneb cmp b jz diff ; " " ; show difference mov c,a call chkhdg; and set delta flag call pausechk lhld base lxi d,address ldax d ! add l ! mov l,a ! inx d ldax d ! adc h ! mov h,a ! inx d ldax d ! aci 0 call .t2hx call .t4hx call tabber mov a,b xra c call .t2hx; show different bits ; " " call show; show file 1 mov b,c call show; show file 2 call .crlf jmp diff ; ; clear variables ; a,f,h,l clear: xra a ! mov h,a ! mov l,a sta flags; default all off sta line; on screen for differences shld base; default 0 dcr a ! dcx h; all 0ffh shld address sta address+2; set to -1 (will increment) ret ; ; show values for b show: call tabber; show file 1 mov a,b call .t2hx; show in hex call blks3 mov a,b call ascii; ascii char or blank call blks3 mov a,b jmp .tadzs; show in decimal ; ; 3 blanks blks3: call blk blks2: call blk jmp blk ; ; Check for the initial header. Mark files not identical. ; a,f,d,e,h,l chkhdg: lxi h,flags push b mov c,m mov a,c ori delta mov m,a xra c pop b rp; delta was already set ; " " ; output page heading ; a,f,d,e,h,l hdg: call .crlf call tabber call tabber lxi d,fcbin lda inuser call .tfnam call tabber lxi d,fcbout lda outuser call .tfnam call .crlf mvi a,7 jmp msg ; ; Tab console over ; a,f tabber: mvi a,tab jmp .couta ; ; show a as char if printable, else as blank ; a,f ascii: ani 07fh cpi 07fh jz blk cpi ' ' jnc .couta ; " " ; blank to console ; a,f blk: mvi a,' ' jmp .couta ; ; check for pagination pause pausechk: mvi a,@csta call .dos ora a cnz abtchk lda flags ani nopause rnz lxi h,line inr m lda lpp; lines per page cmp m rnc mvi m,0 mvi a,8 call msg; [more] pc1: call abtchk cpi cr jnz pc1 mvi a,9 call msg; wipe out the [more] jmp hdg ; ; console char ready - check for abort. Return char. ; a,f abtchk: mvi a,@cin call .dos cpi 3 jz boot; cntrl-c ret ; ; EOF on file1, check for eof on file 2 donea: lhld @outbuff call .bfgetc mvi a,5 jnc exit; file 1 shorter lda flags ora a jm boot; differences mvi a,6; same length jmp exit; files identical ; ; EOF on file2 and not file1 doneb: mvi a,4 ; " " ; Output message no. (a) and exit ; a,f,d,e,h,l exit: call msg jmp boot ; ; output message # (a) ; a,f,h,l msg: lxi h,msgtbl add a mov e,a ! mvi d,0 ! dad d mov e,m ! inx h ! mov d,m mvi a,9 jmp .dos ; msgtbl: dw msg0, msg1, msg2, msg3, msg4 dw msg5, msg6, msg7, msg8, msg9 ; msg0: db 'FDIFF v', ver/10+'0', '.', ver MOD 10 + '0' db ' by C.B. Falconer.',cr,lf,lf db 'Usage: FDIFF [-n000] [d[u]:]file1.ft [d[u]:][file2.ft]' db cr,lf,lf db ' Default file2 is file1 when du''s different',cr,lf db ' Optional -n for no page pauses, -000 (hex) sets base' db cr,lf,lf db 'ex: FDIFF -100 a3:fdiff.obj',cr,lf db 'compare a3:fdiff.obj with current du:fdiff.obj,' db ' using addresses from 0100h' db cr,lf,'$' msg1: db 'Can''t find file1$' msg2: db 'Can''t find file2$' msg3: db 'File2 is same file as file1$' msg4: db 'file2 EOF before file1$' msg5: db 'file1 EOF before file2$' msg6: db 'No differences$' msg7: db 'Addr.',tab,'bits',tab,'Hex Asc. Dec.',tab db 'Hex Asc. Dec.',cr,lf,'$' msg8: db '[more]$' msg9: db ' $' ; ; jam file 2 name to file 1 name filejam: push h ! push d ! push b lxi d,fcbout+1 lxi h,fcbin+1 mvi b,11 fj1: mov a,m ! ani 7fh; delete attrib bits stax d ! inx h ! inx d dcr b ! jnz fj1; more pop b ! pop d ! pop h ret ; ; check for same output file as input, or no output ; a,f,b,c,d,e,h,l (allowed) chksame: lda outuser mov b,a lda inuser xra b ani 01fh rnz; in/out different lxi h,fcbout lxi d,fcbin mvi b,12; check for different drives chk4: ldax d ! xra m; ignore attrib bits. ani 7fh ! rnz; in/out different inx h ! inx d dcr b ! jnz chk4; check more mvi a,3 jmp exit; files same if here ; ; If either file is of type .COM, and base has not been set, ; jam the base value to 0100h. chkcom: lhld base mov a,l ! ora h ! rnz; already set lxi d,fcbin+9 call cmp lxi d,fcbout+9 cnz cmp; check fcbout if not fcbin.COM rnz; not a .com file lxi h,0100h shld base ret ; ; compare de^ for "COM". z flag if so cmp: lxi h,comtyp mvi b,3 cmp1: ldax d ! cmp m ! rnz dcr b ! jnz cmp1 ret ; comtyp: db 'COM' ; ; setup sets the appropriate flag and returns the next char ; a,f,h,l setup: lxi h,flags cpi 'N' jnz setup3 mvi a,nopause ora m ! mov m,a jmp .nextch ; ; check for numeric input setup3: call .qnum rc; not a valid option lxi h,0 setup4: ani 0fh dad h ! dad h ! dad h ! dad h ora l ! mov l,a call .nextch call qhex jnc setup4 shld base cmc ret ; ; check for valid hex digit, convert if so, ; else return carry and unchanged a ; a,f qhex: call .qnum rnc cpi 'A' rc cpi 'F'+1 cmc rc sui 7 ret ; ; increment 24 bit long word hl^ in memory incrm: inr m ! rnz inx h ! inr m ! rnz inx h ! inr m ret ; ; --------- Data Segment -------- ; Link this AFTER all the code segments ; dseg flags: ds 1; verify flag base: ds 2; display base address: ds 3; current display address line: ds 1; on current screen inuser: ds 1; user # for input file fcbin: ds 36; input file fcb outuser: ds 1; user # for output file fcbout: ds 36; output file fcb @outbuff: ds 2; location of 2nd file buffer ; ; This must be the last program storage, see linking above. ; Now uses BUFFLIB .endata. Alternatively use a separate dseg file. ;buffer: ds 0; =.endata; actually rest of memory ; end