;************************************************************************ ; ; 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 inserted before . ; Lines deleted before . ; Lines changed to . ; ; 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+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: