From 80ab2fddfdf30f09f0a0a637654cbb3cd5c7baa6 Mon Sep 17 00:00:00 2001 From: Rich Turner Date: Fri, 12 Aug 1983 17:53:34 -0700 Subject: MS-DOS v2.0 Release --- v2.0/source/FC.ASM | 1684 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1684 insertions(+) create mode 100644 v2.0/source/FC.ASM (limited to 'v2.0/source/FC.ASM') diff --git a/v2.0/source/FC.ASM b/v2.0/source/FC.ASM new file mode 100644 index 0000000..21ed991 --- /dev/null +++ b/v2.0/source/FC.ASM @@ -0,0 +1,1684 @@ + title File Compare Routine for MSDOS 2.0 + +;-----------------------------------------------------------------------; +; Revision History: ; +; ; +; V1.0 Rev. 0 10/27/82 M.A.Ulloa ; +; ; +; Rev. 1 10/28/82 M.A.Ulloa ; +; Changed switch names and added binary compare using the ; +; -b switch. ; +; ; +; Rev. 1 11/4/82 A.R. Reynolds ; +; Messages in separate module ; +; Also added header for MSVER ; +; ; +; Rev. 2 11/29/82 M.A. Ulloa ; +; Corrected sysntex problem with references to [base...] ; +; ; +; Rev. 3 01/03/83 M.A. Ulloa ; +; Stack is right size now. ; +; ; +;-----------------------------------------------------------------------; + +FALSE equ 0 +TRUE equ 0ffh + + +buf_size equ 4096 ;buffer size + + +;-----------------------------------------------------------------------; +; Description ; +; ; +; FC [-# -b -w -c] ; +; ; +; Options: ; +; ; +; -# were # is a number from 1 to 9, how many lines have to ; +; before the end of an area of difference ends. ; +; ; +; -b will force a binary comparation of both files. ; +; ; +; -w will cause all spaces and tabs to be compressed to a single ; +; space before comparing. All leading and trailing spaces and/or tabs ; +; in a line are ignored. ; +; ; +; -c will cause FC to ignore the case of the letters. ; +; ; +; Algorithm for text compare: (The one for binary comp. is trivial) ; +; ; +; The files are read into two separate buffers and the ; +; comparation starts. If two lines are found to be different in the ; +; two buffers, say line i of buffer A and line j of buffer B differ. ; +; The program will try to match line i with line j+1, then with line ; +; j+2 and so on, if the end of buffer is reached the program will ; +; recompact the buffer and try to read more lines into the buffer, if ; +; no more lines can be read because either the buffer is full, or the ; +; end of file was reached, then it will revert and try to match line ; +; j of buffer B to line i+1, i+2 and so on of buffer A. If an end of ; +; buffer is found, it tries to refill it as before. If no matches are ; +; found, then it will try to match line i+1 of buffer A to line j+1, ; +; j+2, j+3, .... of buffer B, if still no matches are found, it reverts ; +; again and tries to match line j+1 of buffer B with lines i+2, i+3,... ; +; of buffer A. And so on till a match is found. ; +; ; +; Once a match is found it continues chcking pairs of lines till ; +; the specified number are matched (option #, 3 by default), and then ; +; it prints the differing area in both files, each followed by the ; +; first line matched. ; +; ; +; If no match is found (the difference is bigger than the buffer) ; +; a "files different" message is printed. ; +; ; +; If one of the files finishes before another the remaining ; +; portion of the file (plus any ongoing difference) is printed out. ; +; ; +;-----------------------------------------------------------------------; + + + subttl Debug Macros + page + +m_debug macro str + local a,b + jmp short b +a db str,0dh,0ah,"$" +b: pushf + push dx + mov dx,offset code:a + push ds + push cs + pop ds + push ax + mov ah,9h + int 21h + pop ax + pop ds + pop dx + popf + endm + + +m_bname macro + local a0,a1,a2,b1,b2 + jmp short a0 +b1 db "------ buffer 1",0dh,0ah,"$" +b2 db "------ buffer 2",0dh,0ah,"$" +a0: pushf + push dx + cmp bx,offset dg:buf1 + je a1 + mov dx,offset code:b2 + jmp short a2 +a1: mov dx,offset code:b1 +a2: push ds + push cs + pop ds + push ax + mov ah,9h + int 21h + pop ax + pop ds + pop dx + popf + endm + + + page + + .SALL + .XLIST + include dossym.asm + .LIST + + subttl General Definitions + page + +CR equ 0dh +LF equ 0ah + + +;-----------------------------------------------------------------------; +; Offsets to buffer structure +; For text comparations: + +fname equ 0 ;file name ptr +fname_len equ 2 ;file name length +handle equ 4 ;handle +curr equ 6 ;current line ptr +lst_curr equ 8 ;last current line ptr +fst_sinc equ 10 ;first line towards a sinc ptr +fst_nosinc equ 12 ;first line out of sinc ptr +dat_end equ 14 ;ptr to last char of the buffer +buf_end equ 16 ;pointer to the end of the buffer +buf equ 18 ;pointer to the buffer + +; For binary comparations: + +by_read equ 6 ;bytes read into buffer + +;-----------------------------------------------------------------------; + + +code segment word +code ends + +const segment public word +const ends + +data segment word +data ends + +dg group code,const,data + + + subttl Constants Area + page + +const segment public word + +make db "MAUlloa/Microsoft/V10" +rev db "2" + +;----- CAREFULL WITH PRESERVING THE ORDER OF THE TABLE ----- +opt_tbl equ $ ;option table + +flg_b db FALSE +flg_c db FALSE +flg_s db FALSE +flg_w db FALSE +;----------------------------------------------------------- + +ib_first1 db FALSE ;flags used when comparing lines +ib_first2 db FALSE ; while in ignore white mode. + +m_num dw 3 ;lines that have to match before + ; reporting a match + +mtch_cntr dw 0 ;matches towards a sinc + +mode db FALSE ;If false then trying to match a line + ; from buf1 to lines in buf2. If true + ; then viceversa. + +sinc db TRUE ;Sinc flag, start IN SINC + +bend db 0 ;binary end of file flag, 0= none yet, + ; 1= file 1 ended, 2= file 2 ended + +base dd 0 ;base address of files for binary + ; comparations + +bhead_flg db false ;true if heading for binary comp. + ; has been printed already. + +;----------------------------------------------------------- +bp_buf equ $ ;binary compare difference template + +bp_buf1 db 8 dup(' ') ;file address + db 3 dup(' ') +bp_buf2 db 2 dup(' ') ;byte of file 1 + db 3 dup(' ') +bp_buf3 db 2 dup(' ') ;byte of file 1 + db CR,LF + +bp_buf_len equ $ - bp_buf ;length of template +;----------------------------------------------------------- + + EXTRN vers_err:byte,opt_err:byte,opt_e:byte,crlf:byte,opt_err_len:byte + EXTRN bhead_len:byte + EXTRN found_err_pre:byte,found_err_pre_len:byte + EXTRN found_err_post:byte,found_err_post_len:byte + EXTRN read_err_pre:byte,read_err_pre_len:byte + EXTRN read_err_post:byte,read_err_post_len:byte + EXTRN file_err:byte,file_err_len:byte + EXTRN bf1ne:byte,bf1ne_len:byte,bf2ne:byte,bf2ne_len:byte,bhead:byte + EXTRN int_err:byte,int_err_len:byte,dif_err:byte,dif_err_len:byte + EXTRN args_err:byte,args_err_len:byte,fname_sep:byte,fname_sep_len:byte + EXTRN diff_sep:byte,diff_sep_len:byte + +const ends + + + + subttl Data Area + page + +data segment word + +com_buf db 128 dup(?) ;command line buffer + +;----- Buffer structures +buf1 dw 11 dup(?) +buf2 dw 11 dup(?) + +; two extra for guard in case of need to insert a CR,LF pair +b1 db buf_size dup(?) +end_b1 db 2 dup(?) +b2 db buf_size dup(?) +end_b2 db 2 dup(?) + +data ends + + + + subttl MAIN Routine + page + +code segment +assume cs:dg,ds:nothing,es:nothing,ss:stack + +start: + jmp short FCSTRT +;-----------------------------------------------------------------------; +; Check version number + +HEADER DB "Vers 1.00" + +FCSTRT: +;Code to print header +; PUSH DS +; push cs +; pop ds +; MOV DX,OFFSET DG:HEADER +; mov ah,std_con_string_output +; int 21h +; POP DS + + mov ah,get_version + int 21h + cmp al,2 + jge vers_ok + mov dx,offset dg:vers_err + mov ah,std_con_string_output + int 21h + push es ;bad vers, exit a la 1.x + xor ax,ax + push ax + +badvex proc far + ret +badvex endp + + +vers_ok: + push cs + pop es + +assume es:dg + +;-----------------------------------------------------------------------; +; Copy command line + + mov si,80h ;command line address + cld + lodsb ;get char count + mov cl,al + xor ch,ch + inc cx ;include the CR + mov di,offset dg:com_buf + cld + rep movsb + + push cs + pop ds + +assume ds:dg + + + +;-----------------------------------------------------------------------; +; Initialize buffer structures + + mov bx,offset dg:buf1 + mov word ptr [bx].buf,offset dg:b1 + mov word ptr [bx].buf_end,offset dg:end_b1 + mov bx,offset dg:buf2 + mov word ptr [bx].buf,offset dg:b2 + mov word ptr [bx].buf_end,offset dg:end_b2 + + +;-----------------------------------------------------------------------; +; Process options + + mov ah,char_oper + mov al,0 + int 21h ;get switch character + mov si,offset dg:com_buf + +cont_opt: + call kill_bl + jc bad_args ;arguments missing + cmp al,dl ;switch character? + jne get_file ;no, process file names + cld + lodsb ;get option + call make_caps ;capitalize option + mov bx,offset dg:opt_tbl + + cmp al,'B' + je b_opt + cmp al,'C' + je c_opt + cmp al,'S' + je s_opt + cmp al,'W' + je w_opt + cmp al,'1' ;a number option? + jb bad_opt + cmp al,'9' + ja bad_opt + and al,0fh ;a number option, convert to binary + xor ah,ah ;zero high nibble + mov [m_num],ax + jmp short cont_opt + +bad_opt: ;a bad option: + push dx ; save switch character + mov [opt_e],al ; option in error + mov dx,offset dg:opt_err + mov cl,opt_err_len + call prt_err ; print error message + pop dx + jmp short cont_opt ; process rest of options + +b_opt: + mov di,0 + jmp short opt_dispatch + +c_opt: + mov di,1 + jmp short opt_dispatch + +s_opt: + mov di,2 + jmp short opt_dispatch + +w_opt: + mov di,3 + +opt_dispatch: + mov byte ptr dg:[bx+di],TRUE ;set the corresponding flag + jmp short cont_opt + + +bad_args: + mov dx,offset dg:args_err + mov cl,args_err_len + jmp an_err + + + +;-----------------------------------------------------------------------; +; Get the file names + +get_file: + dec si ;adjust pointer + call find_nonb ;find first non blank in com. buffer + jc bad_args ;file (or files) missing + mov byte ptr [di],0 ;nul terminate + mov dx,si ;pointer to file name + mov bx,offset dg:buf1 + mov word ptr [bx].fname,dx ;save pointer to file name + mov word ptr [bx].fname_len,cx ;file name length + mov ah,open + mov al,0 ;open for reading + int 21h + jc bad_file + mov word ptr [bx].handle,ax ;save the handle + + mov si,di + inc si ;point past the nul + call kill_bl ;find other file name + jc bad_args ;a CR found: file name missing + dec si ;adjust pointer + call find_nonb + mov byte ptr [di],0 ;nul terminate the file name + mov dx,si + mov bx,offset dg:buf2 + mov word ptr [bx].fname,dx ;save pointer to file name + mov word ptr [bx].fname_len,cx ;file name length + mov ah,open + mov al,0 ;open for reading + int 21h + jc bad_file + mov word ptr [bx].handle,ax ;save the handle + jmp short go_compare + +bad_file: + cmp ax,error_file_not_found + je sj01 + mov dx,offset dg:int_err + mov cl,int_err_len + jmp short an_err +sj01: + push cx ;save file name length + mov dx,offset dg:found_err_pre + mov cl,found_err_pre_len + call prt_err + pop cx + mov dx,si ;pointer to file name length + call prt_err + mov dx,offset dg:found_err_post + mov cl,found_err_post_len +an_err: + call prt_err + mov al,-1 ;return an error code + mov ah,exit + int 21h + + + +;-----------------------------------------------------------------------; +; CHECK COMPARE MODE + +go_compare: + cmp [flg_b],true ;do we do a binary comparation? + je bin_compare + jmp txt_compare + + + subttl Binary Compare Routine + page + +;-----------------------------------------------------------------------; +; COMPARE BUFFERS IN BINARY MODE + +bin_compare: + +;----- Fill in the buffers + + mov bx,offset dg:buf1 ;pointer to buffer structure + mov dx,word ptr[bx].buf ;pointer to buffer + mov si,dx ;save for latter comparation + call read_dat ;read into buffer + jc bad_datj ;an error + mov word ptr[bx].by_read,AX ;save ammount read + push ax ;save for now + + mov bx,offset dg:buf2 ;pointer to buffer structure + mov dx,word ptr[bx].buf ;pointer to buffer + mov di,dx ;save for comparation + call read_dat ;read into buffer +bad_datj: jc bad_dat ;an error + mov word ptr[bx].by_read,AX ;save ammount read + + pop cx ;restore byte count of buffer1 + cmp ax,cx ;compare byte counts + ja morein_b2 + jb morein_b1 + or ax,ax ;the same ammount, is it 0? + jne go_bcomp ;no,compare + jmp go_quit ;yes, all done.... + +morein_b2: + mov [bend],1 ;file 1 ended + jmp short go_bcomp + +morein_b1: + mov [bend],2 ;file 2 ended + mov cx,ax + +;----- Compare data in buffers + +go_bcomp: + mov ax,word ptr [base] ;load base addrs. to AX,BX pair + mov bx,word ptr [base+2] + add bx,cx ;add to base num. of bytes to + adc ax,0 ; compare. + mov word ptr [base],ax ;save total + mov word ptr [base+2],bx + +next_bcomp: + cld + jcxz end_check + repz cmpsb ;compare both buffers + jz end_check ;all bytes match + push cx ;save count so far + push ax + push bx + inc cx + sub bx,cx ;get file address of bytes that + sbb ax,0 ; are different. + call prt_bdif ;print difference + pop bx + pop ax + pop cx ;restore on-going comparation count + jmp short next_bcomp + +bnot_yet: + jmp bin_compare + +end_check: + cmp [bend],0 ;have any file ended yet? + je bnot_yet ;no, read in more data + cmp [bend],1 ;yes, was it file 1? + je bf1_ended ;yes, data left in file 2 + mov dx,offset dg:bf1ne + mov cl,bf1ne_len + jmp short bend_mes + +bf1_ended: + mov dx,offset dg:bf2ne + mov cl,bf2ne_len + +bend_mes: + xor ch,ch + call prout + jmp go_quit + + + + subttl Text Compare Routine + page + +;-----------------------------------------------------------------------; +; Fill in the buffers + +bad_dat: + mov dx,offset dg:file_err + mov cl,file_err_len + jmp an_err + + +txt_compare: + + mov bx,offset dg:buf1 + mov dx,word ptr [bx].buf + mov word ptr [bx].fst_nosinc,dx + mov word ptr [bx].curr,dx + + call fill_buffer + jc bad_dat + + mov bx,offset dg:buf2 + mov dx,word ptr [bx].buf + mov word ptr [bx].fst_nosinc,dx + mov word ptr [bx].curr,dx + + call fill_buffer + jc bad_dat + + +;-----------------------------------------------------------------------; +; COMPARE BUFFERS IN TEXT MODE + +another_line: + call go_match ;try to match both current lines + jc sj02 ;a match + jmp no_match ;no match, continue.... +sj02: + cmp byte ptr[sinc],true ;are we in SINC? + je sj04 + mov ax,[mtch_cntr] + or ax,ax ;first line of a possible SINC? + jnz sj03 + mov bx,offset dg:buf1 + mov word ptr [bx].fst_sinc,si ;yes, save curr line buffer 1 + mov bx,offset dg:buf2 + mov word ptr [bx].fst_sinc,di ;save curr line buffer 2 +sj03: + inc ax ;increment match counter + mov [mtch_cntr],ax ;save number of matches + cmp m_num,ax ;enough lines matched for a SINC? + jne sj04 ;not yet, match some more + mov [sinc],true ;yes, flag we are now in sinc + call print_diff ;print mismatched lines + + + +;-----------------------------------------------------------------------; +; Advance current line pointer in both buffers + +sj04: + mov bx,offset dg:buf1 + call adv_b + jnc sj05 + jmp no_more1 +sj05: + mov word ptr[bx].curr,si + mov bx,offset dg:buf2 + call adv_b + jnc sj051 + jmp no_more2 +sj051: + mov word ptr[bx].curr,si + jmp another_line ;continue matching + + + +;-----------------------------------------------------------------------; +; Process a mismatch + +no_match: + cmp [sinc],true ;are we in SINC? + jne sj06 + mov [sinc],false ;not any more.... + mov bx,offset dg:buf1 + mov word ptr [bx].fst_nosinc,si ;save current lines + mov word ptr [bx].lst_curr,si + mov bx,offset dg:buf2 + mov word ptr [bx].fst_nosinc,di + mov word ptr [bx].lst_curr,di +sj06: + mov [mtch_cntr],0 ;reset match counter + cmp [mode],true + je sj09 + +;----- MODE A ----- + mov bx,offset dg:buf2 + call adv_b ;get next line in buffer (or file) + jc sj08 ;no more lines in buffer +sj07: + mov word ptr [bx].curr,si + jmp another_line +sj08: + mov [mode],true ;change mode + mov si,word ptr [bx].lst_curr + mov word ptr [bx].curr,si + mov bx,offset dg:buf1 + mov si,word ptr [bx].lst_curr + mov word ptr [bx].curr,si + call adv_b ;get next line + jc no_more1 ;no more lines fit in buffer 1 + mov word ptr [bx].lst_curr,si + jmp short sj10 + +;----- MODE B ----- +sj09: + mov bx,offset dg:buf1 + call adv_b ;get next line in buffer (or file) + jc sj11 ;no more lines in buffer +sj10: + mov word ptr [bx].curr,si + jmp another_line + +sj11: + mov [mode],false + mov si,word ptr [bx].lst_curr + mov word ptr [bx].curr,si + mov bx,offset dg:buf2 + mov si,word ptr [bx].lst_curr + mov word ptr [bx].curr,si + call adv_b ;get next line + jc no_more2 ;no more lines fit in buffer 2 + mov word ptr [bx].lst_curr,si + jmp sj07 + + + +;-----------------------------------------------------------------------; +; Process end of files + +no_more1: + cmp ax,0 ;end of file reached? + jz xj1 + jmp dif_files ;no, difference was too big +xj1: + cmp [sinc],true ;file1 ended, are we in SINC? + je xj3 + jmp no_sinc +xj3: + mov bx,offset dg:buf2 + call adv_b ;advance current line in buf2 + jnc xj5 + jmp go_quit ;file2 ended too, terminate prog. +xj5: + +;----- File 1 ended but NOT file 2 + mov bx,offset dg:buf1 + call print_head + mov bx,offset dg:buf2 + call print_head + call print_all ;print the rest of file2 + jmp go_quit + + +no_more2: + cmp ax,0 ;end of file reached? + jz xj2 + jmp dif_files ;no, difference was too big +xj2: + cmp [sinc],true ;file1 ended, are we in SINC? + je xj4 + jmp no_sinc +xj4: + mov bx,offset dg:buf1 + call adv_b ;advance current line in buf2 + jnc xj6 + jmp go_quit ;file2 ended too, terminate prog. +xj6: + +;----- File 2 ended but NOT file 1 + mov bx,offset dg:buf1 + call print_head + call print_all ;print the rest of file1 + mov bx,offset dg:buf2 + call print_head + jmp go_quit + + + +no_sinc: + mov bx,offset dg:buf1 + call print_head + call print_all + mov bx,offset dg:buf2 + call print_head + call print_all + jmp go_quit + + + +dif_files: + mov dx,offset dg:dif_err + mov cl,dif_err_len + jmp an_err + +go_quit: + mov al,0 + mov ah,exit + int 21h + + + subttl Subroutines: make caps + page + +;-----------------------------------------------------------------------; +; CAPIALIZES THE CHARACTER IN AL ; +; ; +; entry: ; +; AL has the character to Capitalize ; +; ; +; exit: ; +; AL has the capitalized character ; +; ; +; Called from MAIN and go_match ; +;-----------------------------------------------------------------------; +make_caps: + cmp al,'a' + jb sa1 + cmp al,'z' + jg sa1 + and al,0dfh +sa1: ret + + + subttl Subroutines: kill_bl + page + +;-----------------------------------------------------------------------; +; Get rid of blanks in command line. ; +; ; +; entry: ; +; SI points to the first character on the line to scan. ; +; ; +; exit: ; +; SI points to the next char after the first non-blank ; +; char found. ; +; Carry Set if a CR found ; +; ; +; modifies: ; +; SI and AX ; +; ; +; Called from MAIN ; +;-----------------------------------------------------------------------; +kill_bl: + cld ;increment +sb1: lodsb ;get rid of blanks + cmp al,' ' + je sb1 + cmp al,9 + je sb1 + cmp al,CR + clc ;assume not a CR + jne sb2 + stc ;a CR found, set carry +sb2: ret + + + subttl Subroutines: find_nonb + page + +;-----------------------------------------------------------------------; +; Find the first non-blank in a line ; +; ; +; entry: ; +; SI points to the line buffer ; +; ; +; exit: ; +; DI pointer to the first blank found (incl. CR) ; +; CX character count of non-blanks ; +; Carry Set if a CR was found ; +; ; +; modifies: ; +; AX ; +; ; +; Called from MAIN ; +;-----------------------------------------------------------------------; +find_nonb: + push si ;save pointer + xor cx,cx ;zero character count + cld +sc1: + lodsb + cmp al,' ' + je sc2 + cmp al,9 + je sc2 + cmp al,CR + je sc2 + inc cx ;inc character count + jmp short sc1 +sc2: + dec si + mov di,si + pop si + cmp al,CR + jne sc3 + stc + ret +sc3: + clc + ret + + + subttl Subroutines: prt_bdif + page + +;-----------------------------------------------------------------------; +; Print a binary difference ; +; ; +; entry: ; +; AX,BX file address of diference ; +; SI pointer to one past byte in buffer1 ; +; DI pointer to one past byte in buffer2 ; +; ; +; modifies: ; +; AX, DX and CX ; +; ; +; called from bin_compare ; +;-----------------------------------------------------------------------; +prt_bdif: + cmp [bhead_flg],true ;have we peinted head yet? + je bhead_ok + mov [bhead_flg],true ;no, set flag + push ax ;print heading + mov dx,offset dg:bhead + mov cl,bhead_len + xor ch,ch + call prout + pop ax + +bhead_ok: + mov dx,di ;conver file address + mov di,offset dg:bp_buf1 + push ax + mov al,ah + call bin2hex + pop ax + call bin2hex + mov al,bh + call bin2hex + mov al,bl + call bin2hex + + mov di,offset dg:bp_buf2 ;convert byte from file 1 + mov al, byte ptr[si-1] + call bin2hex + + mov di,offset dg:bp_buf3 ;convert byte from file 2 + push si + mov si,dx + mov al, byte ptr[si-1] + pop si + call bin2hex + + mov di,dx ;print result + mov dx,offset dg:bp_buf + mov cx,bp_buf_len + call prout + ret + + + subttl Subroutines: bin2hex + page + +;-----------------------------------------------------------------------; +; Binary to ASCII hex conversion ; +; ; +; entry: ; +; AL byte to convert ; +; DI pointer to were the two result ASCII bytes should go ; +; ; +; exit: ; +; DI points to one past were the last result byte whent ; +; ; +; modifies: ; +; AH and CL ; +; ; +; Called from prt_bdif ; +;-----------------------------------------------------------------------; +bin2hex: + mov cl,4 + ror ax,cl ;get the high nibble + and al,0fh ;mask of high nible + call pt_hex + rol ax,cl ;get the low nibble + and al,0fh ;mask.... + +pt_hex: + cmp al,0ah ;is it past an A ? + jae pasta + add al,30h + jmp short put_hex +pasta: + add al,37h +put_hex: + stosb ;place in buffer + ret + + + subttl Subroutines: go_match + page + +;-----------------------------------------------------------------------; +; Match current lines ; +; ; +; exit: ; +; Carry set if the match reset otherwise ; +; SI Current line of buff1 ; +; DI Current line of buff2 ; +; ; +; ; +; modifies: ; +; AX,BX,CX,DX and BP ; +; ; +; Called from txt_compare ; +;-----------------------------------------------------------------------; +go_match: + mov bx,offset dg:buf1 + mov si,word ptr[bx].curr + push si + mov bp,si ;save line pointer + call find_eol + mov dx,cx ;save length of line + mov bx,offset dg:buf2 + mov si,word ptr[bx].curr + push si + mov di,si + call find_eol + cmp cx,dx ;compare lengths + jne sd1 ;they do not match + mov si,bp ;restore line pointer + jcxz sd4 ;both length = 0, they match + push cx ;save the length + cld + repz cmpsb ;compare strings + pop cx ;restore the length + jz sd4 ;they match +sd1: + cmp [flg_w],true ;do we ignore multiple whites? + je ib_compare ;yes, go compare + cmp [flg_c],true ;do we ignore case differences? + je ic_compare ;yes, go compare +sd3: + clc ;they don't match + jmp short sd5 +sd4: + stc +sd5: + pop di ;curr2 + pop si ;curr1 + ret + + + page + +;-----------------------------------------------------------------------; +; Compare ignoring case differences. + +ic_compare: + pop di ;get pointer to lines + pop si + push si ;re-save pointers + push di +sd8: + mov al,byte ptr [si] ;get next char. of first line + call make_caps + mov bl,al ;save capitalized char + mov al,byte ptr [di] ;get next chra. of second line + call make_caps + cmp al,bl + jne sd3 ;they do not match.... + inc si ;advance pointers + inc di + loop sd8 ;loop for the line lengths + jmp short sd4 ;they match + + + page + +;-----------------------------------------------------------------------; +; Compare compressing whites and ignoring case differences if +; desired too. + +ib_compare: + mov [ib_first1],true ;we start by the first char in the + mov [ib_first2],true ; in the lines. + pop di ;get pointer to lines + pop si + push si ;re-save pointers + push di +sd9: + mov al,byte ptr [si] ;get next char. of first line + call isa_white ;is it a white? + jnc sd12 ;no, compare.... +sd10: + mov al,byte ptr [si+1] ;peek to next, + call isa_white ; it is a white too? + jnc sd11 + inc si ; yes, + jmp short sd10 ; compress all whites to a blank +sd11: + cmp [ib_first1],true ;is this the first char. of the line? + jne sd111 ;no, it stays a white + inc si ;ignore the white + jmp short sd12 +sd111: + cmp al,CR ;is this the last char. of the line + jne sd112 ;no, it stays a white + inc si ;yes, ignore the whites + jmp short sd12 +sd112: + mov al,' ' ;no more whites found + +sd12: + cmp [ib_first1],true ;is this the first char. of the line? + jne sd121 ;no, continue + mov [ib_first1],false ;yes, reset the flag +sd121: + cmp [flg_c],true ;do we ignore case? + jne sd122 ;no,.... + call make_caps +sd122: + mov bl,al ;save char + mov al,byte ptr [di] ;get next chra. of second line + call isa_white + jnc sd15 +sd13: + mov al,byte ptr [di+1] ;peek to next as before + call isa_white + jnc sd14 + inc di + jmp short sd13 +sd14: + cmp [ib_first2],true ;is this the first char. of the line? + jne sd141 ;no, it stays a white + inc di ;ignore the white + jmp short sd15 +sd141: + cmp al,CR ;is this the last char. of the line + jne sd142 ;no, it stays a white + inc si ;yes, ignore the whites + jmp short sd15 +sd142: + mov al,' ' + +sd15: + cmp [ib_first2],true ;is this the first char. of the line? + jne sd151 ;no, continue + mov [ib_first2],false ;yes, reset the flag +sd151: + cmp [flg_c],true ;do we ignore case? + jne sd152 ;no,.... + call make_caps +sd152: + cmp al,bl + je sd153 + jmp sd3 ;they do not match.... +sd153: + cmp al,CR ;have we reached the end? + jne sd154 ;no, continue.... + jmp sd4 ;yes, they match +sd154: + inc si ;no, advance pointers + inc di + jmp sd9 ;loop for the line lengths + + +isa_white: + cmp al,' ' ;is it a space? + je sdx1 + cmp al,09h ;is it a tab? + je sdx1 + clc ;if not a white return with carry clear + ret +sdx1: + stc ;is a white return with carry set + ret + + + page + +;-----------------------------------------------------------------------; +find_eol: + xor cx,cx ;zero count + cld +sd6: + lodsb + cmp al,CR + je sd7 + inc cx + jmp short sd6 +sd7: + ret + + + subttl Subroutines: adv_b + page + +;-----------------------------------------------------------------------; +; Get the next line in the buffer ; +; ; +; It will attempt to get the next current line from the buffer ; +; if it fails, it will force a refill, and if some data is read in ; +; then it will return the next current line. ; +; ; +; entry: ; +; BX pointer to buffer structure ; +; ; +; exit: ; +; SI pointer to next line (if any) ; +; Carry set if no more lines available. If carry set then: ; +; AX End Code: 0 = end of file reached ; +; 1 = no room in buffer for a line ; +; ; +; modifies: ; +; CX,DX and DI ; +; ; +; Called from txt_compare ; +;-----------------------------------------------------------------------; +adv_b: + call get_nextl + jc se1 + ret +se1: + call refill + jnc se0 + ret +se0: + call get_nextl + ret + + + subttl Subroutines: get_nextl + page + +;-----------------------------------------------------------------------; +; Returns the next line in a buffer ; +; (next from current or next from pointer) ; +; ; +; entry: ; +; BX pointer to buffer structure ; +; (SI pointer to line, if calling get_next) ; +; ; +; exit: ; +; SI pointer to next line ; +; Carry set if no more lines available ; +; ; +; modifies: ; +; DI and CX ; +; ; +; Called from adv_b and print_diff (in the case of get_next) ; +;-----------------------------------------------------------------------; +get_nextl: + mov si,word ptr [bx].curr +get_next: + mov cx,word ptr [bx].dat_end + sub cx,si + mov di,si + mov al,LF + cld + repnz scasb + mov si,di ;pointer to next line + jnz se2 ;not found + clc + ret +se2: + inc si ;point past the LF + stc + ret + + + subttl Subroutines: refill + page + +;-----------------------------------------------------------------------; +; Refill a buffer ; +; ; +; It will refill a buffer with data from the corresponding ; +; file. It will first recompact the buffer to make room for the new ; +; data. If in SINC then it will move the current line to the top of ; +; the buffer, and read the data from the end of this line till the ; +; end of the buffer. ; +; If NOT in SINC then it will recompact the buffer by moving ; +; all lines between the first to go out of SINC till the current line ; +; to the top of the buffer, and then reading data after the current ; +; line. ; +; When recompacting the buffer it relocates all pointers to ; +; point to the new locations of the respective lines. ; +; Some of the pointers may be pointing to meaningless locations ; +; before the relocation, and consecuently they will be pointing to ; +; even less meaningfull locations after relocation. ; +; After reading the data it normalizes the buffer to make sure ; +; that no partially full lines are present at the end of the buffer. If ; +; after recompacting and reading some character it is found that the ; +; characters read do not constitute a full line, then it will return ; +; with an error code. It will also return with an error code if it ; +; attempts to read past the end of file. ; +; ; +; entry: ; +; BX pointer to buffer structure ; +; ; +; exit: ; +; Carry set if no chars read into the buffer. If carry set then: ; +; AX End Code: 0 = end of file reached ; +; 1 = no room in the buffer for a line ; +; ; +; modifies: ; +; CX,DX,SI and DI ; +; ; +; Called from adv_b ; +;-----------------------------------------------------------------------; +refill: + +;----- Calculate ammount to move & pointer relocation factor. + + cmp [sinc],true + jne sf1 + mov si,word ptr [bx].curr + jmp short sf2 +sf1: + mov si,word ptr [bx].fst_nosinc +sf2: + mov di,word ptr [bx].buf + mov cx,word ptr [bx].dat_end + + mov dx,si ;calculate pointer relocation factor + sub dx,di ;DX = factor + jz sf3 ;no room in buffer + sub cx,si ;calculate ammount of data to move + inc cx ;CX = ammount + +;----- Move data + + cld ;auto decrement + rep movsb + +;----- Relocate pointers + + sub word ptr [bx].curr,dx + sub word ptr [bx].lst_curr,dx + sub word ptr [bx].fst_sinc,dx + sub word ptr [bx].fst_nosinc,dx + sub word ptr [bx].dat_end,dx + +sf3: + mov dx,word ptr [bx].dat_end + inc dx ;empty part starts here + +;----- fill the buffer + + call fill_buffer + ret + + + subttl Subroutines: fill_buffer + page + +;-----------------------------------------------------------------------; +; Fill the data buffers ; +; ; +; It will fill the buffer from the pointer to the end of buffer ; +; and normalize the buffer. ; +; ; +; entry: ; +; BX pointer to buffer structure ; +; DX pointer to buffer (or part of buffer) ; +; ; +; exit: ; +; Carry set if no chars read into the buffer. If carry set then: ; +; AX End Code: 0 = end of file reached ; +; 1 = no room in the buffer for a line ; +; ; +; modifies: ; +; AX,CX,DX and DI ; +; ; +; Called from txt_compare and refill ; +;-----------------------------------------------------------------------; +fill_buffer: + push bx + call read_dat ;get data + jc bad_read + or ax,ax ;zero chars read? + jz rd_past_eof + call nor_buf + mov di,cx ;save normalized char. count + mov bp,dx ;save data end for now + +;----- seek for old partial line + + or ax,ax ;is the seek value = 0 ? + jz sg1 ;yes, do not seek + mov dx,ax + neg dx + mov cx,-1 + mov al,1 ;seek from current position + mov ah,lseek + int 21h + jc bad_read ;error mesage (BX already in stack) + +sg1: + mov cx,di ;restore normalized char count. + or cx,cx ;char count = 0 due to normalization? + jz no_room + + pop bx + mov word ptr [bx].dat_end,bp + clc + ret + +bad_read: + mov dx,offset dg:read_err_pre + mov cl,read_err_pre_len + call prt_err ;print error message + pop bx + mov dx,word ptr[bx].fname + mov cx,word ptr[bx].fname_len + call prt_err ;print file name + mov dx,offset dg:read_err_post + mov cl,read_err_post_len + jmp an_err + +no_room: + mov ax,1 + jmp short sg2 + +rd_past_eof: + xor ax,ax +sg2: + pop bx + stc + ret + + + subttl Subroutines: read_dat + page + +;-----------------------------------------------------------------------; +; ; +; entry: ; +; DX pointer to data area (buffer or part of buffer) ; +; ; +; exit: ; +; AX character count or error code (from DOS read) ; +; Carry set if error condition ; +; ; +; modifies: ; +; BX and CX ; +; ; +; Called from fill_buffer, print_all and bin_compare ; +;-----------------------------------------------------------------------; +read_dat: + mov cx,word ptr [bx].buf_end + mov bx,word ptr [bx].handle + sub cx,dx ;ammount to read to buff1 + mov ah,read + int 21h + ret + + + subttl Subroutines: nor_buf + page + +;-----------------------------------------------------------------------; +; Normalize buffers so they do not have partially full ; +; lines at the end. If character count is less than the buffer size ; +; then it checks that the last line is terminated by a CR,LF pair. ; +; If it is not it inserts a CR,LF at the end. It returns a seek value ; +; for the buffer corresponding to the number of characters in the ; +; incomplete line at the end of the buffer (if any). This can be used ; +; to start reading from the beggining of the incomplete line on next ; +; time the buffer is loaded. ; +; ; +; ENTRY: ; +; DX buffer pointer ; +; AX character count read ; +; CX character count requested ; +; ; +; EXIT: ; +; DX pointer to last char in buffer (normalized) ; +; CX character count (normalized) ; +; AX seek value ; +; ; +; MODIFIES: ; +; DI ; +; ; +; Called from fill_buffer ; +;-----------------------------------------------------------------------; +nor_buf: + mov di,dx + add di,ax + dec di ;points to last char in buffer + cmp ax,cx ;were all chars. requested read? + je sm7 ;yes, buffer full + cmp byte ptr[di],1ah ;terminated with a ^Z ? + jne sm1 + dec di ;point to previous character + dec ax ;decrement character count +sm1: cmp byte ptr[di],lf ;is last char a LF? + je sm6 + cmp byte ptr[di],cr ;is it a CR then? + je sm5 + add ax,2 ;two more chars in buffer + inc di +sm2: mov byte ptr[di],cr +sm3: inc di + mov byte ptr[di],lf +sm4: mov cx,ax ;new character count + mov dx,di ;pointer to last char + xor ax,ax ;seek = 0 + ret + +sm5: + inc ax ;one more char in buffer + jmp short sm3 + +sm6: + cmp byte ptr[di-1],cr ;is previous char a CR? + je sm4 + inc ax ;no, one more char in buffer + jmp short sm2 + +sm7: + push ax ;save char count + mov cx,ax + mov al,LF + std + repnz scasb ;search for last LF + pop ax ;restore char count + jnz bad_line ;none found, line too big + inc di ;point to last LF + mov dx,di + inc cx ;ammount of chars in buffer + sub ax,cx ;seek value + ret + +bad_line: ;full line not possible, return + mov dx,di ; with AX=count, CX=0 and DX= + ret ; old last char in buffer pointer. + + + + subttl Subroutines: print_diff + page + +;-----------------------------------------------------------------------; +; print the difference between buffers ; +; ; +; It will print the mismatched lines. First it prints a heading ; +; with the first file name, then the lines that differ from file 1, ; +; then a heading with the second file name, and then the lines that ; +; differ in file 2 . ; +; The lines that differ are considered to start from fst_nosinc ; +; till fst_sinc. ; +; ; +; Called from txt_compare ; +;-----------------------------------------------------------------------; +print_diff: + mov bx,offset dg:buf1 + call print_head ;print heading for file 1 + mov dx,word ptr [bx].fst_nosinc + mov si,word ptr [bx].fst_sinc + call get_next ;get pointer to next line + mov cx,si + sub cx,dx ;get character count + call prout + mov bx,offset dg:buf2 + call print_head ;print heading for file 1 + mov dx,word ptr [bx].fst_nosinc + mov si,word ptr [bx].fst_sinc + call get_next ;get pointer to next line + mov cx,si + sub cx,dx ;get character count + call prout + mov dx,offset dg:diff_sep + mov cl,diff_sep_len + xor ch,ch + call prout ;print difference separator + ret + + + subttl Subroutines: print_head + page + +;-----------------------------------------------------------------------; +; Print heading for difference ; +; ; +; entry: ; +; BX pointer to buffer structure ; +; ; +; modifies: ; +; AX,CX and DX ; +; ; +; Called from txt_compare and print_diff ; +;-----------------------------------------------------------------------; +print_head: + mov dx,offset dg:fname_sep + mov cl,fname_sep_len + xor ch,ch + call prout + mov dx,word ptr [bx].fname + mov cx,word ptr [bx].fname_len + call prout + mov dx,offset dg:CRLF + mov cx,2 + call prout + ret + + + subttl Subroutines: print_all + page + +;-----------------------------------------------------------------------; +; Print the rest of a file ; +; ; +; If in SINC it will print the file from the fst_nosinc line ; +; till the end of the file. If NOT in SINC then it will print from ; +; the current line of the buffer to the end of the file. ; +; ; +; entry: ; +; BX pointer to buffer structure ; +; ; +; modifies: ; +; AX,CX and DX ; +; ; +; Called from txt_compare ; +;-----------------------------------------------------------------------; +print_all: + cmp [sinc],true ;are we in SINC? + jne so1 + mov dx,word ptr [bx].curr + jmp short so2 +so1: + mov dx,word ptr [bx].fst_nosinc +so2: + mov cx,word ptr [bx].dat_end + inc cx + +prt_again: + sub cx,dx ;ammount of data to write + call prout ;write it out + +;----- Read more data to the buffer + push bx ;save pointer to buffer struct + mov dx,word ptr [bx].buf + call read_dat + jnc so3 + jmp bad_read ;print error (BX in stack) +so3: + or ax,ax ;zero chars read? + jne so4 + pop bx ;all done writting + ret +so4: + pop bx + mov cx,word ptr [bx].buf_end + jmp short prt_again ;print next buffer full + + + subttl Subroutines: prout and prt_err + page + +;-----------------------------------------------------------------------; +; ; +;-----------------------------------------------------------------------; +prout: + push bx + mov bx,stdout + mov ah,write + int 21h + pop bx + ret + + +;-----------------------------------------------------------------------; +; ; +;-----------------------------------------------------------------------; +prt_err: + push bx + xor ch,ch + jcxz retpbx + mov bx,stderr + mov ah,write + int 21h +retpbx: + pop bx + ret + +code ends + + page + + +stack segment stack + + dw 128 dup(?) + +stack ends + + + end start + \ No newline at end of file -- cgit v1.2.3