mirror of
https://github.com/microsoft/MS-DOS.git
synced 2024-11-29 17:15:47 +00:00
1684 lines
64 KiB
NASM
1684 lines
64 KiB
NASM
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] <file1> <file2> ;
|
||
; ;
|
||
; 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
|
||
|