Davex/src/xtn/2/cmpf.asm
2018-09-16 21:01:16 -04:00

974 lines
14 KiB
NASM

;************************************************************************
;
; Davex external command CMPF (compare text files)
;
; Programmed by Kevin R. Cooper, April 12, 1989.
;
; This program compares two text files on a line by
; line basis. The changes that must be made to file A
; to transform it to file B are reported.
;
; Possible change reports are:
;
; Lines <B line range> inserted before <A line #>.
; Lines <A line range> deleted before <B line #>.
; Lines <A line range> changed to <B line range>.
;
; At the end of the comparison the number of differences
; between the files is reported.
;
; The parameter MIN_LINES is the minimum number of lines
; which must match between files to resynchronize after a
; mismatch.
;
; Notes:
;
; ! Remember never to put comments on EDASM macro
; lines!
; - Number of differences and line numbers are two-byte
; numbers. Should be three-byte numbers; would be faster
; to use decimal arithmetic.
; - Buffering of rea.resy blocks could be more efficient.
;
; (1) Original coding. (KRC 13-Mar-89)
; (2) Treats EOF as CR; added spacebar wait. (KRC 22-Mar-89)
; (3) Last character of file is an EOLN, not EOF
; is CR. (KRC 3-Apr-89)
; (4) Better resynch algorithm. (KRC 4-Apr-89)
; (5) Written as a Davex external command. (KRC 9-Apr-89)
;
;************************************************************************
;
; Converted to MPW IIgs 20-Sep-92 DAL
;
;************************************************************************
.include "Common/2/Globals2.asm"
.include "Common/2/Mli.globals2.asm"
.include "Common/Macros.asm"
;
.segment "CODE_A000"
default_min = 3
default_mask = $7f
.macro inc_p Arg
.local ok
INC Arg
BNE ok
INC Arg+1
ok:
.endmacro
.macro poke_p Arg1,Arg2
LDA #<Arg2
STA Arg1
LDA #>Arg2
STA Arg1+1
.endmacro
.macro copy_p Arg1,Arg2
LDA Arg1
STA Arg2
LDA Arg1+1
STA Arg2+1
.endmacro
.macro copy_t Arg1,Arg2
LDA Arg1
STA Arg2
LDA Arg1+1
STA Arg2+1
LDA Arg1+2
STA Arg2+2
.endmacro
.macro eq_t Arg1,Arg2
.local notEq
LDA Arg1
CMP Arg2
BNE notEq
LDA Arg1+1
CMP Arg2+1
BNE notEq
LDA Arg1+2
CMP Arg2+2
notEq:
.endmacro
.macro zero_p Arg
lda #0
sta Arg
sta Arg+1
.endmacro
.macro zero_t Arg
lda #0
sta Arg
sta Arg+1
sta Arg+2
.endmacro
.macro inc_t Arg
.local ok
INC Arg
BNE ok
INC Arg+1
BNE ok
INC Arg+2
ok:
.endmacro
.macro isz_t Arg
LDA Arg
ORA Arg+1
ORA Arg+2
.endmacro
.macro dec_t Arg
.local ok
.local ok2
LDA Arg
BNE ok
LDA Arg+1
BNE ok2
DEC Arg+2
ok2: DEC Arg+1
ok: DEC Arg
.endmacro
.macro dec_p Arg
.local ok
LDA Arg
BNE ok
DEC Arg+1
ok: DEC Arg
.endmacro
.macro ld_ay Arg
LDY Arg
LDA Arg+1
.endmacro
orgadr = $a000
MyVersion = $09
MinVersion = $12
;
;----------------------
;
; org orgadr
;
; Davex command info
;
rts
.byte $ee,$ee
.byte MyVersion,MinVersion
.byte %00000000 ;hardware req
.addr descr
.addr orgadr
.addr start
.byte 0,0,0,0
;
; parameters here
;
.byte 0,t_wildpath
.byte 0,t_wildpath
.byte $80+'n',t_int1
.byte 0,0
;
descr: pstr "compare text files--by Kevin R. Cooper"
;
;----------------------
;
; dum xczpage
Mask = xczpage ;.res 1
a_pos = Mask+1 ;.res 3
a_line = a_pos+3 ;.res 2
;
a_eof = a_line+2 ;.res 3
a_eoln_flag = a_eof+3 ;.res 1
;
b_pos = a_eoln_flag+1 ;.res 3
b_line = b_pos+3 ;.res 2
;
b_eof = b_line+2 ;.res 3
b_eoln_flag = b_eof+3 ;.res 1
; dend
;
a_open_buff = filebuff
b_open_buff = filebuff2
;
; dum filebuff3
b_max_pos = filebuff3 ;.res 3
b_max_line = b_max_pos+3 ;.res 2
min_lines = b_max_line+2 ;.res 1
num_diffs = min_lines+1 ;.res 2
line_count = num_diffs+2 ;.res 1 ;used by match_n_lines
line_num = line_count+1 ;.res 2
a2_pos = line_num+2 ;.res 3
a2_line = a2_pos+3 ;.res 2
;
a_min_pos = a2_line+2 ;.res 3
a_min_line = a_min_pos+3 ;.res 2
;
b2_pos = a_min_line+2 ;.res 3
b2_line = b2_pos+3 ;.res 2
;
lastBmaxFlg = b2_line+2 ;.res 1
; dend
;
;----------------------
;
hi_bit = $80
cr = $8d
locr = cr-hi_bit
ctrl = $40
;
;----------------------
;
crout = $fd8e
cout = $fded
;
;----------------------
;
start:
;====
;
; get A path parameter
;
; lda #0
; jsr xgetparm_n
sty a_name
sta a_name+1
;
; get B path paramter
;
lda #1
jsr xgetparm_n
sty b_name
sta b_name+1
;
; get MIN_LINES paramter
;
lda #'n'+$80
jsr xgetparm_ch
bcc got_min_lines
lda #default_min
got_min_lines: sta min_lines
;
lda #default_mask
sta Mask
;
jsr open_a
jsr get_a_eof
;
jsr open_b
jsr get_b_eof
;
jsr crout
;
compare_files:
zero_p num_diffs
;
zero_t a_pos
zero_t b_pos
;
poke_p a_line,1
poke_p b_line,1
;
zero_t a_mark
zero_t b_mark
;
;----------------------
;
compare: ;a_pos = a_mark = a file pos, etc. b
eq_t a_pos,a_eof
beq got_an_eof
;
eq_t b_pos,b_eof
beq got_an_eof
;
;----------------------
;
jsr xcheck_wait
jsr match_line
beq synched
jmp resynch
;
synched:
;
copy_t a_mark,a_pos
inc_p a_line
;
copy_t b_mark,b_pos
inc_p b_line
;
jmp compare
;
;----------------------
;
got_an_eof:
;---------
;
copy_t a_eof,a2_pos
copy_t b_eof,b2_pos
;
jsr report_diff
;
jsr xmess
asc "Number of differences: "
.byte 0
;
ld_ay num_diffs
jsr xprdec_2
jmp crout ;rts to Davex
;
;----------------------
;
resynch:
;------
copy_p b_line,b_max_line
copy_t b_pos,b_max_pos
;
copy_p a_line,a_min_line
copy_t a_pos,a_min_pos
;
lsr lastBmaxFlg
;
;----------------------
;
resynch1:
;-------
copy_p a_min_line,a2_line
copy_t a_min_pos,a2_pos
;
copy_p b_max_line,b2_line
copy_t b_max_pos,b2_pos
;
;----------------------
;
resynch2:
;-------
copy_t a2_pos,a_mark
jsr set_a_mark
;
copy_t b2_pos,b_mark
jsr set_b_mark
;
jsr xcheck_wait
;
;----------------------
;
jsr match_n_lines
bne not_resynch
;
jmp resynched
;
;----------------------
;
not_resynch:
;
eq_t b2_pos,b_pos
bne next_a2_line
;
go_exit_loop2: jmp exit_loop2
;
;----------------------
;
next_a2_line: copy_t a2_pos,a_mark
jsr set_a_mark
;
next_a2: jsr read_a
bit a_eoln_flag
bpl next_a2
;
eq_t a_mark,a_eof
beq go_exit_loop2
;
copy_t a_mark,a2_pos
inc_p a2_line
;
;----------------------
;
last_b2_line:
;
copy_t b2_pos,b_mark
dec_t b_mark
;
last_b2:
;
isz_t b_mark
beq got_last_b2
;
dec_t b_mark
jsr set_b_mark
jsr read_b
bit b_eoln_flag
bmi got_last_b2
;
dec_t b_mark
jmp last_b2
;
got_last_b2:
;
copy_t b_mark,b2_pos
dec_p b2_line
;
jmp resynch2
;
;----------------------
;
exit_loop2:
;
bit lastBmaxFlg
bmi NextAminLine
;
eq_t b2_pos,b_eof
beq NextAminLine
;
;----------------------
;
NextBmaxLine: copy_t b_max_pos,b_mark
jsr set_b_mark
;
next_b_max: jsr read_b
bit b_eoln_flag
bpl next_b_max
;
eq_t b_mark,b_eof
beq GotLstBmax
;
copy_t b_mark,b_max_pos
inc_p b_max_line
;
jmp resynch1
;
;----------------------
;
GotLstBmax: ror lastBmaxFlg ;carry set by eq_t
;
NextAminLine:
;
copy_t a_min_pos,a_mark
jsr set_a_mark
;
next_a_min: jsr read_a
bit a_eoln_flag
bpl next_a_min
;
eq_t a_mark,a_eof
beq cant_resynch
;
copy_t a_mark,a_min_pos
inc_p a_min_line
;
jmp resynch1
;
cant_resynch: jmp got_an_eof
;
;----------------------
;
resynched: jsr report_diff
;
copy_p a2_line,a_line
copy_t a2_pos,a_pos
copy_t a_pos,a_mark
jsr set_a_mark
;
copy_p b2_line,b_line
copy_t b2_pos,b_pos
copy_t b_pos,b_mark
jsr set_b_mark
;
jmp compare
;
;----------------------
;
match_n_lines: ;x_eof must not be true
;============
lda min_lines
sta line_count
;
mn: jsr match_line
bne mn_failed
;
dec line_count
beq matched_n
;
eq_t a_mark,a_eof
beq mn_failed
;
eq_t b_mark,b_eof
bne mn
;
lda #1
;
mn_failed: rts ;z flag clear
;
matched_n: rts ;match succeeded ;z flag set
;
;----------------------
;
; using current file positions and x_mark-s;
; returns x_mark-s
;
match_line:
;=========
jsr read_a
jsr read_b
;
lda a_read_buff
cmp b_read_buff
bne ml_failed
;
lda a_eoln_flag
and b_eoln_flag
bmi matched_line
;
lda a_eoln_flag
ora b_eoln_flag
bpl match_line ;if not ( eoln(a) or eoln(b) ) then continue
;
ml_failed: lda #1
rts ;match line failed; z flag clear
;
matched_line: lda #0
rts ;match line succeeded; z flag set
;
;----------------------
;
report_diff: ; a_pos, b_pos = start of unsynch; a2_pos, b2_pos = resynch
;==========
eq_t a_pos,a2_pos
bne rd2
;
eq_t b_pos,b2_pos
bne report_ins
;
rts
;
rd2: eq_t b_pos,b2_pos
beq report_del
;
jmp report_chg
;
;----------------------
;
report_ins:
;---------
jsr list_b_lines
jsr xmess
.byte cr
asc "inserted before"
.byte cr,cr,0
jsr list_a_line
jmp got_diff
;
;----------------------
;
report_del:
;---------
jsr list_a_lines
jsr xmess
.byte cr
asc "deleted before"
.byte cr,cr,0
jsr list_b_line
jmp got_diff
;
;----------------------
;
report_chg:
;---------
jsr list_a_lines
jsr xmess
.byte cr
asc "changed to"
.byte cr,cr,0
jsr list_b_lines
jmp got_diff
;
;----------------------
;
got_diff:
;-------
inc_p num_diffs
jsr crout
jmp crout ;rts
;
;----------------------
;
list_a_lines: ;list a_line .. a2_line-1 @ a_pos .. a2_pos-1
;===========
jsr goto_a_line
;
list_a:
;
jsr list_a_line2
;
inc_p line_num
eq_t a_mark,a2_pos
bne list_a
;
rts
;
;----------------------
;
list_a_line: ;list line a_line starting at a_pos
;==========
;
jsr goto_a_line
jmp list_a_line2 ;rts
;
;----------------------
;
goto_a_line:
;==========
copy_p a_line,line_num
;
copy_t a_pos,a_mark
jmp set_a_mark ; rts
;
;----------------------
;
list_a_line2:
;===========
jsr xcheck_wait
;
eq_t a_mark,a_eof
beq print_a_eof
;
lda #'A'+$80
jsr cout
;
ld_ay line_num
jsr xprdec_2
;
lda #' '+$80
jsr cout
;
;----------------------
;
print_a_line:
;
jsr read_a
;
lda a_read_buff
ora #hi_bit
jsr cout
;
bit a_eoln_flag
bpl print_a_line
;
cmp #cr
beq PrintedLineA
;
jmp crout ;rts ;need cr because eof was eoln
;
PrintedLineA: rts
;
;----------------------
;
print_a_eof:
;
jsr xmess
asc "end of file A"
.byte cr,0
rts
;
;----------------------
;
list_b_lines: ;list b_line .. b2_line-1 @ b_pos .. b2_pos-1
;===========
jsr goto_b_line
;
list_b:
;
jsr list_b_line2
;
inc_p line_num
eq_t b_mark,b2_pos
bne list_b
;
rts
;
;----------------------
;
list_b_line: ;list line b_line starting at b_pos
;==========
;
jsr goto_b_line
jmp list_b_line2 ; rts
;
;----------------------
;
goto_b_line:
;==========
copy_p b_line,line_num
;
copy_t b_pos,b_mark
jmp set_b_mark ;rts
;
;----------------------
;
list_b_line2:
;===========
jsr xcheck_wait
;
eq_t b_mark,b_eof
beq print_b_eof
;
lda #'B'+$80
jsr cout
;
ld_ay line_num
jsr xprdec_2
;
lda #' '+$80
jsr cout
;
;----------------------
;
print_b_line:
;
jsr read_b
;
lda b_read_buff
ora #hi_bit
jsr cout
;
bit b_eoln_flag
bpl print_b_line
;
cmp #cr
beq PrintedLineB
;
jmp crout ;rts ;need cr because eof was eoln
;
PrintedLineB: rts
;
;----------------------
;
print_b_eof:
;
jsr xmess
asc "end of file B"
.byte cr,0
rts
;
;----------------------
;
open_a:
;==========
jsr mli
.byte $c8 ;open
.addr a_open_parms
bcs open_a_err
;
lda a_ref
sta a_mark_ref
sta a_read_ref
;
rts
;
open_a_err: jmp xProDOS_err
;
;----------------------
;
a_open_parms: .byte 3
a_name: .res 2
.addr a_open_buff
a_ref: .res 1
;
;----------------------
;
open_b:
;==========
jsr mli
.byte $c8 ;open
.addr b_open_parms
bcs open_b_err
;
lda b_ref
sta b_mark_ref
sta b_read_ref
;
rts
;
open_b_err: jmp xProDOS_err
;
;----------------------
;
b_open_parms: .byte 3
b_name: .res 2
.addr b_open_buff
b_ref: .res 1
;
;----------------------
;
; enter read_a and read_b with x_mark and current
; file pos synchronized; x_read_buff has char and
; x_mark inc-ed; sets flag x_eoln_flag if char=locr
; or x_mark = x_eof-1
;
read_a:
;==========
;
jsr mli
.byte $ca ;read
.addr a_read_parms
bcs a_read_err
;
inc_t a_mark
;
lda a_read_buff
and Mask
sta a_read_buff
cmp #locr
beq got_a_eoln
;
eq_t a_mark,a_eof
beq got_a_eoln
;
lsr a_eoln_flag
rts
;
got_a_eoln: ror a_eoln_flag ;carry is set by cmp #locr or eq_t
rts
;
a_read_err: jmp xProDOS_err
;
;----------------------
;
a_read_parms:
.byte 4
a_read_ref:
.res 1
.addr a_read_buff
a_read_len:
.addr 1
ReadActLenA:
.res 2
;
a_read_buff:
.res 1
;
;----------------------
;
read_b:
;==========
;
jsr mli
.byte $ca ;read
.addr b_read_parms
bcs b_read_err
;
inc_t b_mark
;
lda b_read_buff
and Mask
sta b_read_buff
cmp #locr
beq got_b_eoln
;
eq_t b_mark,b_eof
beq got_b_eoln
;
lsr b_eoln_flag
rts
;
got_b_eoln: ror b_eoln_flag ;carry is set by cmp #locr or eq_t
rts
;
b_read_err: jmp xProDOS_err
;
;----------------------
;
b_read_parms:
.byte 4
b_read_ref:
.res 1
.addr b_read_buff
b_read_len:
.addr 1
ReadActLenB:
.res 2
;
b_read_buff:
.res 1
;
;----------------------
;
get_a_eof:
;========
jsr mli
.byte $d1 ;get eof
.addr a_mark_parms
bcs get_a_eof_err
;
copy_t a_mark,a_eof
rts
;
get_a_eof_err: jmp xProDOS_err
;
;----------------------
;
a_mark_parms: .byte 2
a_mark_ref: .res 1
a_mark: .res 3
;
;----------------------
;
set_a_mark:
;========
jsr mli
.byte $ce ;set mark
.addr a_mark_parms
bcs SetMarkErrA
;
rts
;
SetMarkErrA: jmp xProDOS_err
;
;----------------------
;
get_b_eof:
;========
jsr mli
.byte $d1 ;get eof
.addr b_mark_parms
bcs get_b_eof_err
;
copy_t b_mark,b_eof
rts
;
get_b_eof_err: jmp xProDOS_err
;
;----------------------
;
b_mark_parms: .byte 2
b_mark_ref: .res 1
b_mark: .res 3
;
;----------------------
;
set_b_mark:
;========
jsr mli
.byte $ce ;set mark
.addr b_mark_parms
bcs SetMarkErrB
;
rts
;
SetMarkErrB: jmp xProDOS_err
;
;----------------------
;
zzz_the_end: