summaryrefslogtreecommitdiff
path: root/v2.0/source/FC.ASM
diff options
context:
space:
mode:
Diffstat (limited to 'v2.0/source/FC.ASM')
-rw-r--r--v2.0/source/FC.ASM1684
1 files changed, 1684 insertions, 0 deletions
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 @@
1 title File Compare Routine for MSDOS 2.0
2
3;-----------------------------------------------------------------------;
4; Revision History: ;
5; ;
6; V1.0 Rev. 0 10/27/82 M.A.Ulloa ;
7; ;
8; Rev. 1 10/28/82 M.A.Ulloa ;
9; Changed switch names and added binary compare using the ;
10; -b switch. ;
11; ;
12; Rev. 1 11/4/82 A.R. Reynolds ;
13; Messages in separate module ;
14; Also added header for MSVER ;
15; ;
16; Rev. 2 11/29/82 M.A. Ulloa ;
17; Corrected sysntex problem with references to [base...] ;
18; ;
19; Rev. 3 01/03/83 M.A. Ulloa ;
20; Stack is right size now. ;
21; ;
22;-----------------------------------------------------------------------;
23
24FALSE equ 0
25TRUE equ 0ffh
26
27
28buf_size equ 4096 ;buffer size
29
30
31;-----------------------------------------------------------------------;
32; Description ;
33; ;
34; FC [-# -b -w -c] <file1> <file2> ;
35; ;
36; Options: ;
37; ;
38; -# were # is a number from 1 to 9, how many lines have to ;
39; before the end of an area of difference ends. ;
40; ;
41; -b will force a binary comparation of both files. ;
42; ;
43; -w will cause all spaces and tabs to be compressed to a single ;
44; space before comparing. All leading and trailing spaces and/or tabs ;
45; in a line are ignored. ;
46; ;
47; -c will cause FC to ignore the case of the letters. ;
48; ;
49; Algorithm for text compare: (The one for binary comp. is trivial) ;
50; ;
51; The files are read into two separate buffers and the ;
52; comparation starts. If two lines are found to be different in the ;
53; two buffers, say line i of buffer A and line j of buffer B differ. ;
54; The program will try to match line i with line j+1, then with line ;
55; j+2 and so on, if the end of buffer is reached the program will ;
56; recompact the buffer and try to read more lines into the buffer, if ;
57; no more lines can be read because either the buffer is full, or the ;
58; end of file was reached, then it will revert and try to match line ;
59; j of buffer B to line i+1, i+2 and so on of buffer A. If an end of ;
60; buffer is found, it tries to refill it as before. If no matches are ;
61; found, then it will try to match line i+1 of buffer A to line j+1, ;
62; j+2, j+3, .... of buffer B, if still no matches are found, it reverts ;
63; again and tries to match line j+1 of buffer B with lines i+2, i+3,... ;
64; of buffer A. And so on till a match is found. ;
65; ;
66; Once a match is found it continues chcking pairs of lines till ;
67; the specified number are matched (option #, 3 by default), and then ;
68; it prints the differing area in both files, each followed by the ;
69; first line matched. ;
70; ;
71; If no match is found (the difference is bigger than the buffer) ;
72; a "files different" message is printed. ;
73; ;
74; If one of the files finishes before another the remaining ;
75; portion of the file (plus any ongoing difference) is printed out. ;
76; ;
77;-----------------------------------------------------------------------;
78
79
80 subttl Debug Macros
81 page
82
83m_debug macro str
84 local a,b
85 jmp short b
86a db str,0dh,0ah,"$"
87b: pushf
88 push dx
89 mov dx,offset code:a
90 push ds
91 push cs
92 pop ds
93 push ax
94 mov ah,9h
95 int 21h
96 pop ax
97 pop ds
98 pop dx
99 popf
100 endm
101
102
103m_bname macro
104 local a0,a1,a2,b1,b2
105 jmp short a0
106b1 db "------ buffer 1",0dh,0ah,"$"
107b2 db "------ buffer 2",0dh,0ah,"$"
108a0: pushf
109 push dx
110 cmp bx,offset dg:buf1
111 je a1
112 mov dx,offset code:b2
113 jmp short a2
114a1: mov dx,offset code:b1
115a2: push ds
116 push cs
117 pop ds
118 push ax
119 mov ah,9h
120 int 21h
121 pop ax
122 pop ds
123 pop dx
124 popf
125 endm
126
127
128 page
129
130 .SALL
131 .XLIST
132 include dossym.asm
133 .LIST
134
135 subttl General Definitions
136 page
137
138CR equ 0dh
139LF equ 0ah
140
141
142;-----------------------------------------------------------------------;
143; Offsets to buffer structure
144; For text comparations:
145
146fname equ 0 ;file name ptr
147fname_len equ 2 ;file name length
148handle equ 4 ;handle
149curr equ 6 ;current line ptr
150lst_curr equ 8 ;last current line ptr
151fst_sinc equ 10 ;first line towards a sinc ptr
152fst_nosinc equ 12 ;first line out of sinc ptr
153dat_end equ 14 ;ptr to last char of the buffer
154buf_end equ 16 ;pointer to the end of the buffer
155buf equ 18 ;pointer to the buffer
156
157; For binary comparations:
158
159by_read equ 6 ;bytes read into buffer
160
161;-----------------------------------------------------------------------;
162
163
164code segment word
165code ends
166
167const segment public word
168const ends
169
170data segment word
171data ends
172
173dg group code,const,data
174
175
176 subttl Constants Area
177 page
178
179const segment public word
180
181make db "MAUlloa/Microsoft/V10"
182rev db "2"
183
184;----- CAREFULL WITH PRESERVING THE ORDER OF THE TABLE -----
185opt_tbl equ $ ;option table
186
187flg_b db FALSE
188flg_c db FALSE
189flg_s db FALSE
190flg_w db FALSE
191;-----------------------------------------------------------
192
193ib_first1 db FALSE ;flags used when comparing lines
194ib_first2 db FALSE ; while in ignore white mode.
195
196m_num dw 3 ;lines that have to match before
197 ; reporting a match
198
199mtch_cntr dw 0 ;matches towards a sinc
200
201mode db FALSE ;If false then trying to match a line
202 ; from buf1 to lines in buf2. If true
203 ; then viceversa.
204
205sinc db TRUE ;Sinc flag, start IN SINC
206
207bend db 0 ;binary end of file flag, 0= none yet,
208 ; 1= file 1 ended, 2= file 2 ended
209
210base dd 0 ;base address of files for binary
211 ; comparations
212
213bhead_flg db false ;true if heading for binary comp.
214 ; has been printed already.
215
216;-----------------------------------------------------------
217bp_buf equ $ ;binary compare difference template
218
219bp_buf1 db 8 dup(' ') ;file address
220 db 3 dup(' ')
221bp_buf2 db 2 dup(' ') ;byte of file 1
222 db 3 dup(' ')
223bp_buf3 db 2 dup(' ') ;byte of file 1
224 db CR,LF
225
226bp_buf_len equ $ - bp_buf ;length of template
227;-----------------------------------------------------------
228
229 EXTRN vers_err:byte,opt_err:byte,opt_e:byte,crlf:byte,opt_err_len:byte
230 EXTRN bhead_len:byte
231 EXTRN found_err_pre:byte,found_err_pre_len:byte
232 EXTRN found_err_post:byte,found_err_post_len:byte
233 EXTRN read_err_pre:byte,read_err_pre_len:byte
234 EXTRN read_err_post:byte,read_err_post_len:byte
235 EXTRN file_err:byte,file_err_len:byte
236 EXTRN bf1ne:byte,bf1ne_len:byte,bf2ne:byte,bf2ne_len:byte,bhead:byte
237 EXTRN int_err:byte,int_err_len:byte,dif_err:byte,dif_err_len:byte
238 EXTRN args_err:byte,args_err_len:byte,fname_sep:byte,fname_sep_len:byte
239 EXTRN diff_sep:byte,diff_sep_len:byte
240
241const ends
242
243
244
245 subttl Data Area
246 page
247
248data segment word
249
250com_buf db 128 dup(?) ;command line buffer
251
252;----- Buffer structures
253buf1 dw 11 dup(?)
254buf2 dw 11 dup(?)
255
256; two extra for guard in case of need to insert a CR,LF pair
257b1 db buf_size dup(?)
258end_b1 db 2 dup(?)
259b2 db buf_size dup(?)
260end_b2 db 2 dup(?)
261
262data ends
263
264
265
266 subttl MAIN Routine
267 page
268
269code segment
270assume cs:dg,ds:nothing,es:nothing,ss:stack
271
272start:
273 jmp short FCSTRT
274;-----------------------------------------------------------------------;
275; Check version number
276
277HEADER DB "Vers 1.00"
278
279FCSTRT:
280;Code to print header
281; PUSH DS
282; push cs
283; pop ds
284; MOV DX,OFFSET DG:HEADER
285; mov ah,std_con_string_output
286; int 21h
287; POP DS
288
289 mov ah,get_version
290 int 21h
291 cmp al,2
292 jge vers_ok
293 mov dx,offset dg:vers_err
294 mov ah,std_con_string_output
295 int 21h
296 push es ;bad vers, exit a la 1.x
297 xor ax,ax
298 push ax
299
300badvex proc far
301 ret
302badvex endp
303
304
305vers_ok:
306 push cs
307 pop es
308
309assume es:dg
310
311;-----------------------------------------------------------------------;
312; Copy command line
313
314 mov si,80h ;command line address
315 cld
316 lodsb ;get char count
317 mov cl,al
318 xor ch,ch
319 inc cx ;include the CR
320 mov di,offset dg:com_buf
321 cld
322 rep movsb
323
324 push cs
325 pop ds
326
327assume ds:dg
328
329
330
331;-----------------------------------------------------------------------;
332; Initialize buffer structures
333
334 mov bx,offset dg:buf1
335 mov word ptr [bx].buf,offset dg:b1
336 mov word ptr [bx].buf_end,offset dg:end_b1
337 mov bx,offset dg:buf2
338 mov word ptr [bx].buf,offset dg:b2
339 mov word ptr [bx].buf_end,offset dg:end_b2
340
341
342;-----------------------------------------------------------------------;
343; Process options
344
345 mov ah,char_oper
346 mov al,0
347 int 21h ;get switch character
348 mov si,offset dg:com_buf
349
350cont_opt:
351 call kill_bl
352 jc bad_args ;arguments missing
353 cmp al,dl ;switch character?
354 jne get_file ;no, process file names
355 cld
356 lodsb ;get option
357 call make_caps ;capitalize option
358 mov bx,offset dg:opt_tbl
359
360 cmp al,'B'
361 je b_opt
362 cmp al,'C'
363 je c_opt
364 cmp al,'S'
365 je s_opt
366 cmp al,'W'
367 je w_opt
368 cmp al,'1' ;a number option?
369 jb bad_opt
370 cmp al,'9'
371 ja bad_opt
372 and al,0fh ;a number option, convert to binary
373 xor ah,ah ;zero high nibble
374 mov [m_num],ax
375 jmp short cont_opt
376
377bad_opt: ;a bad option:
378 push dx ; save switch character
379 mov [opt_e],al ; option in error
380 mov dx,offset dg:opt_err
381 mov cl,opt_err_len
382 call prt_err ; print error message
383 pop dx
384 jmp short cont_opt ; process rest of options
385
386b_opt:
387 mov di,0
388 jmp short opt_dispatch
389
390c_opt:
391 mov di,1
392 jmp short opt_dispatch
393
394s_opt:
395 mov di,2
396 jmp short opt_dispatch
397
398w_opt:
399 mov di,3
400
401opt_dispatch:
402 mov byte ptr dg:[bx+di],TRUE ;set the corresponding flag
403 jmp short cont_opt
404
405
406bad_args:
407 mov dx,offset dg:args_err
408 mov cl,args_err_len
409 jmp an_err
410
411
412
413;-----------------------------------------------------------------------;
414; Get the file names
415
416get_file:
417 dec si ;adjust pointer
418 call find_nonb ;find first non blank in com. buffer
419 jc bad_args ;file (or files) missing
420 mov byte ptr [di],0 ;nul terminate
421 mov dx,si ;pointer to file name
422 mov bx,offset dg:buf1
423 mov word ptr [bx].fname,dx ;save pointer to file name
424 mov word ptr [bx].fname_len,cx ;file name length
425 mov ah,open
426 mov al,0 ;open for reading
427 int 21h
428 jc bad_file
429 mov word ptr [bx].handle,ax ;save the handle
430
431 mov si,di
432 inc si ;point past the nul
433 call kill_bl ;find other file name
434 jc bad_args ;a CR found: file name missing
435 dec si ;adjust pointer
436 call find_nonb
437 mov byte ptr [di],0 ;nul terminate the file name
438 mov dx,si
439 mov bx,offset dg:buf2
440 mov word ptr [bx].fname,dx ;save pointer to file name
441 mov word ptr [bx].fname_len,cx ;file name length
442 mov ah,open
443 mov al,0 ;open for reading
444 int 21h
445 jc bad_file
446 mov word ptr [bx].handle,ax ;save the handle
447 jmp short go_compare
448
449bad_file:
450 cmp ax,error_file_not_found
451 je sj01
452 mov dx,offset dg:int_err
453 mov cl,int_err_len
454 jmp short an_err
455sj01:
456 push cx ;save file name length
457 mov dx,offset dg:found_err_pre
458 mov cl,found_err_pre_len
459 call prt_err
460 pop cx
461 mov dx,si ;pointer to file name length
462 call prt_err
463 mov dx,offset dg:found_err_post
464 mov cl,found_err_post_len
465an_err:
466 call prt_err
467 mov al,-1 ;return an error code
468 mov ah,exit
469 int 21h
470
471
472
473;-----------------------------------------------------------------------;
474; CHECK COMPARE MODE
475
476go_compare:
477 cmp [flg_b],true ;do we do a binary comparation?
478 je bin_compare
479 jmp txt_compare
480
481
482 subttl Binary Compare Routine
483 page
484
485;-----------------------------------------------------------------------;
486; COMPARE BUFFERS IN BINARY MODE
487
488bin_compare:
489
490;----- Fill in the buffers
491
492 mov bx,offset dg:buf1 ;pointer to buffer structure
493 mov dx,word ptr[bx].buf ;pointer to buffer
494 mov si,dx ;save for latter comparation
495 call read_dat ;read into buffer
496 jc bad_datj ;an error
497 mov word ptr[bx].by_read,AX ;save ammount read
498 push ax ;save for now
499
500 mov bx,offset dg:buf2 ;pointer to buffer structure
501 mov dx,word ptr[bx].buf ;pointer to buffer
502 mov di,dx ;save for comparation
503 call read_dat ;read into buffer
504bad_datj: jc bad_dat ;an error
505 mov word ptr[bx].by_read,AX ;save ammount read
506
507 pop cx ;restore byte count of buffer1
508 cmp ax,cx ;compare byte counts
509 ja morein_b2
510 jb morein_b1
511 or ax,ax ;the same ammount, is it 0?
512 jne go_bcomp ;no,compare
513 jmp go_quit ;yes, all done....
514
515morein_b2:
516 mov [bend],1 ;file 1 ended
517 jmp short go_bcomp
518
519morein_b1:
520 mov [bend],2 ;file 2 ended
521 mov cx,ax
522
523;----- Compare data in buffers
524
525go_bcomp:
526 mov ax,word ptr [base] ;load base addrs. to AX,BX pair
527 mov bx,word ptr [base+2]
528 add bx,cx ;add to base num. of bytes to
529 adc ax,0 ; compare.
530 mov word ptr [base],ax ;save total
531 mov word ptr [base+2],bx
532
533next_bcomp:
534 cld
535 jcxz end_check
536 repz cmpsb ;compare both buffers
537 jz end_check ;all bytes match
538 push cx ;save count so far
539 push ax
540 push bx
541 inc cx
542 sub bx,cx ;get file address of bytes that
543 sbb ax,0 ; are different.
544 call prt_bdif ;print difference
545 pop bx
546 pop ax
547 pop cx ;restore on-going comparation count
548 jmp short next_bcomp
549
550bnot_yet:
551 jmp bin_compare
552
553end_check:
554 cmp [bend],0 ;have any file ended yet?
555 je bnot_yet ;no, read in more data
556 cmp [bend],1 ;yes, was it file 1?
557 je bf1_ended ;yes, data left in file 2
558 mov dx,offset dg:bf1ne
559 mov cl,bf1ne_len
560 jmp short bend_mes
561
562bf1_ended:
563 mov dx,offset dg:bf2ne
564 mov cl,bf2ne_len
565
566bend_mes:
567 xor ch,ch
568 call prout
569 jmp go_quit
570
571
572
573 subttl Text Compare Routine
574 page
575
576;-----------------------------------------------------------------------;
577; Fill in the buffers
578
579bad_dat:
580 mov dx,offset dg:file_err
581 mov cl,file_err_len
582 jmp an_err
583
584
585txt_compare:
586
587 mov bx,offset dg:buf1
588 mov dx,word ptr [bx].buf
589 mov word ptr [bx].fst_nosinc,dx
590 mov word ptr [bx].curr,dx
591
592 call fill_buffer
593 jc bad_dat
594
595 mov bx,offset dg:buf2
596 mov dx,word ptr [bx].buf
597 mov word ptr [bx].fst_nosinc,dx
598 mov word ptr [bx].curr,dx
599
600 call fill_buffer
601 jc bad_dat
602
603
604;-----------------------------------------------------------------------;
605; COMPARE BUFFERS IN TEXT MODE
606
607another_line:
608 call go_match ;try to match both current lines
609 jc sj02 ;a match
610 jmp no_match ;no match, continue....
611sj02:
612 cmp byte ptr[sinc],true ;are we in SINC?
613 je sj04
614 mov ax,[mtch_cntr]
615 or ax,ax ;first line of a possible SINC?
616 jnz sj03
617 mov bx,offset dg:buf1
618 mov word ptr [bx].fst_sinc,si ;yes, save curr line buffer 1
619 mov bx,offset dg:buf2
620 mov word ptr [bx].fst_sinc,di ;save curr line buffer 2
621sj03:
622 inc ax ;increment match counter
623 mov [mtch_cntr],ax ;save number of matches
624 cmp m_num,ax ;enough lines matched for a SINC?
625 jne sj04 ;not yet, match some more
626 mov [sinc],true ;yes, flag we are now in sinc
627 call print_diff ;print mismatched lines
628
629
630
631;-----------------------------------------------------------------------;
632; Advance current line pointer in both buffers
633
634sj04:
635 mov bx,offset dg:buf1
636 call adv_b
637 jnc sj05
638 jmp no_more1
639sj05:
640 mov word ptr[bx].curr,si
641 mov bx,offset dg:buf2
642 call adv_b
643 jnc sj051
644 jmp no_more2
645sj051:
646 mov word ptr[bx].curr,si
647 jmp another_line ;continue matching
648
649
650
651;-----------------------------------------------------------------------;
652; Process a mismatch
653
654no_match:
655 cmp [sinc],true ;are we in SINC?
656 jne sj06
657 mov [sinc],false ;not any more....
658 mov bx,offset dg:buf1
659 mov word ptr [bx].fst_nosinc,si ;save current lines
660 mov word ptr [bx].lst_curr,si
661 mov bx,offset dg:buf2
662 mov word ptr [bx].fst_nosinc,di
663 mov word ptr [bx].lst_curr,di
664sj06:
665 mov [mtch_cntr],0 ;reset match counter
666 cmp [mode],true
667 je sj09
668
669;----- MODE A -----
670 mov bx,offset dg:buf2
671 call adv_b ;get next line in buffer (or file)
672 jc sj08 ;no more lines in buffer
673sj07:
674 mov word ptr [bx].curr,si
675 jmp another_line
676sj08:
677 mov [mode],true ;change mode
678 mov si,word ptr [bx].lst_curr
679 mov word ptr [bx].curr,si
680 mov bx,offset dg:buf1
681 mov si,word ptr [bx].lst_curr
682 mov word ptr [bx].curr,si
683 call adv_b ;get next line
684 jc no_more1 ;no more lines fit in buffer 1
685 mov word ptr [bx].lst_curr,si
686 jmp short sj10
687
688;----- MODE B -----
689sj09:
690 mov bx,offset dg:buf1
691 call adv_b ;get next line in buffer (or file)
692 jc sj11 ;no more lines in buffer
693sj10:
694 mov word ptr [bx].curr,si
695 jmp another_line
696
697sj11:
698 mov [mode],false
699 mov si,word ptr [bx].lst_curr
700 mov word ptr [bx].curr,si
701 mov bx,offset dg:buf2
702 mov si,word ptr [bx].lst_curr
703 mov word ptr [bx].curr,si
704 call adv_b ;get next line
705 jc no_more2 ;no more lines fit in buffer 2
706 mov word ptr [bx].lst_curr,si
707 jmp sj07
708
709
710
711;-----------------------------------------------------------------------;
712; Process end of files
713
714no_more1:
715 cmp ax,0 ;end of file reached?
716 jz xj1
717 jmp dif_files ;no, difference was too big
718xj1:
719 cmp [sinc],true ;file1 ended, are we in SINC?
720 je xj3
721 jmp no_sinc
722xj3:
723 mov bx,offset dg:buf2
724 call adv_b ;advance current line in buf2
725 jnc xj5
726 jmp go_quit ;file2 ended too, terminate prog.
727xj5:
728
729;----- File 1 ended but NOT file 2
730 mov bx,offset dg:buf1
731 call print_head
732 mov bx,offset dg:buf2
733 call print_head
734 call print_all ;print the rest of file2
735 jmp go_quit
736
737
738no_more2:
739 cmp ax,0 ;end of file reached?
740 jz xj2
741 jmp dif_files ;no, difference was too big
742xj2:
743 cmp [sinc],true ;file1 ended, are we in SINC?
744 je xj4
745 jmp no_sinc
746xj4:
747 mov bx,offset dg:buf1
748 call adv_b ;advance current line in buf2
749 jnc xj6
750 jmp go_quit ;file2 ended too, terminate prog.
751xj6:
752
753;----- File 2 ended but NOT file 1
754 mov bx,offset dg:buf1
755 call print_head
756 call print_all ;print the rest of file1
757 mov bx,offset dg:buf2
758 call print_head
759 jmp go_quit
760
761
762
763no_sinc:
764 mov bx,offset dg:buf1
765 call print_head
766 call print_all
767 mov bx,offset dg:buf2
768 call print_head
769 call print_all
770 jmp go_quit
771
772
773
774dif_files:
775 mov dx,offset dg:dif_err
776 mov cl,dif_err_len
777 jmp an_err
778
779go_quit:
780 mov al,0
781 mov ah,exit
782 int 21h
783
784
785 subttl Subroutines: make caps
786 page
787
788;-----------------------------------------------------------------------;
789; CAPIALIZES THE CHARACTER IN AL ;
790; ;
791; entry: ;
792; AL has the character to Capitalize ;
793; ;
794; exit: ;
795; AL has the capitalized character ;
796; ;
797; Called from MAIN and go_match ;
798;-----------------------------------------------------------------------;
799make_caps:
800 cmp al,'a'
801 jb sa1
802 cmp al,'z'
803 jg sa1
804 and al,0dfh
805sa1: ret
806
807
808 subttl Subroutines: kill_bl
809 page
810
811;-----------------------------------------------------------------------;
812; Get rid of blanks in command line. ;
813; ;
814; entry: ;
815; SI points to the first character on the line to scan. ;
816; ;
817; exit: ;
818; SI points to the next char after the first non-blank ;
819; char found. ;
820; Carry Set if a CR found ;
821; ;
822; modifies: ;
823; SI and AX ;
824; ;
825; Called from MAIN ;
826;-----------------------------------------------------------------------;
827kill_bl:
828 cld ;increment
829sb1: lodsb ;get rid of blanks
830 cmp al,' '
831 je sb1
832 cmp al,9
833 je sb1
834 cmp al,CR
835 clc ;assume not a CR
836 jne sb2
837 stc ;a CR found, set carry
838sb2: ret
839
840
841 subttl Subroutines: find_nonb
842 page
843
844;-----------------------------------------------------------------------;
845; Find the first non-blank in a line ;
846; ;
847; entry: ;
848; SI points to the line buffer ;
849; ;
850; exit: ;
851; DI pointer to the first blank found (incl. CR) ;
852; CX character count of non-blanks ;
853; Carry Set if a CR was found ;
854; ;
855; modifies: ;
856; AX ;
857; ;
858; Called from MAIN ;
859;-----------------------------------------------------------------------;
860find_nonb:
861 push si ;save pointer
862 xor cx,cx ;zero character count
863 cld
864sc1:
865 lodsb
866 cmp al,' '
867 je sc2
868 cmp al,9
869 je sc2
870 cmp al,CR
871 je sc2
872 inc cx ;inc character count
873 jmp short sc1
874sc2:
875 dec si
876 mov di,si
877 pop si
878 cmp al,CR
879 jne sc3
880 stc
881 ret
882sc3:
883 clc
884 ret
885
886
887 subttl Subroutines: prt_bdif
888 page
889
890;-----------------------------------------------------------------------;
891; Print a binary difference ;
892; ;
893; entry: ;
894; AX,BX file address of diference ;
895; SI pointer to one past byte in buffer1 ;
896; DI pointer to one past byte in buffer2 ;
897; ;
898; modifies: ;
899; AX, DX and CX ;
900; ;
901; called from bin_compare ;
902;-----------------------------------------------------------------------;
903prt_bdif:
904 cmp [bhead_flg],true ;have we peinted head yet?
905 je bhead_ok
906 mov [bhead_flg],true ;no, set flag
907 push ax ;print heading
908 mov dx,offset dg:bhead
909 mov cl,bhead_len
910 xor ch,ch
911 call prout
912 pop ax
913
914bhead_ok:
915 mov dx,di ;conver file address
916 mov di,offset dg:bp_buf1
917 push ax
918 mov al,ah
919 call bin2hex
920 pop ax
921 call bin2hex
922 mov al,bh
923 call bin2hex
924 mov al,bl
925 call bin2hex
926
927 mov di,offset dg:bp_buf2 ;convert byte from file 1
928 mov al, byte ptr[si-1]
929 call bin2hex
930
931 mov di,offset dg:bp_buf3 ;convert byte from file 2
932 push si
933 mov si,dx
934 mov al, byte ptr[si-1]
935 pop si
936 call bin2hex
937
938 mov di,dx ;print result
939 mov dx,offset dg:bp_buf
940 mov cx,bp_buf_len
941 call prout
942 ret
943
944
945 subttl Subroutines: bin2hex
946 page
947
948;-----------------------------------------------------------------------;
949; Binary to ASCII hex conversion ;
950; ;
951; entry: ;
952; AL byte to convert ;
953; DI pointer to were the two result ASCII bytes should go ;
954; ;
955; exit: ;
956; DI points to one past were the last result byte whent ;
957; ;
958; modifies: ;
959; AH and CL ;
960; ;
961; Called from prt_bdif ;
962;-----------------------------------------------------------------------;
963bin2hex:
964 mov cl,4
965 ror ax,cl ;get the high nibble
966 and al,0fh ;mask of high nible
967 call pt_hex
968 rol ax,cl ;get the low nibble
969 and al,0fh ;mask....
970
971pt_hex:
972 cmp al,0ah ;is it past an A ?
973 jae pasta
974 add al,30h
975 jmp short put_hex
976pasta:
977 add al,37h
978put_hex:
979 stosb ;place in buffer
980 ret
981
982
983 subttl Subroutines: go_match
984 page
985
986;-----------------------------------------------------------------------;
987; Match current lines ;
988; ;
989; exit: ;
990; Carry set if the match reset otherwise ;
991; SI Current line of buff1 ;
992; DI Current line of buff2 ;
993; ;
994; ;
995; modifies: ;
996; AX,BX,CX,DX and BP ;
997; ;
998; Called from txt_compare ;
999;-----------------------------------------------------------------------;
1000go_match:
1001 mov bx,offset dg:buf1
1002 mov si,word ptr[bx].curr
1003 push si
1004 mov bp,si ;save line pointer
1005 call find_eol
1006 mov dx,cx ;save length of line
1007 mov bx,offset dg:buf2
1008 mov si,word ptr[bx].curr
1009 push si
1010 mov di,si
1011 call find_eol
1012 cmp cx,dx ;compare lengths
1013 jne sd1 ;they do not match
1014 mov si,bp ;restore line pointer
1015 jcxz sd4 ;both length = 0, they match
1016 push cx ;save the length
1017 cld
1018 repz cmpsb ;compare strings
1019 pop cx ;restore the length
1020 jz sd4 ;they match
1021sd1:
1022 cmp [flg_w],true ;do we ignore multiple whites?
1023 je ib_compare ;yes, go compare
1024 cmp [flg_c],true ;do we ignore case differences?
1025 je ic_compare ;yes, go compare
1026sd3:
1027 clc ;they don't match
1028 jmp short sd5
1029sd4:
1030 stc
1031sd5:
1032 pop di ;curr2
1033 pop si ;curr1
1034 ret
1035
1036
1037 page
1038
1039;-----------------------------------------------------------------------;
1040; Compare ignoring case differences.
1041
1042ic_compare:
1043 pop di ;get pointer to lines
1044 pop si
1045 push si ;re-save pointers
1046 push di
1047sd8:
1048 mov al,byte ptr [si] ;get next char. of first line
1049 call make_caps
1050 mov bl,al ;save capitalized char
1051 mov al,byte ptr [di] ;get next chra. of second line
1052 call make_caps
1053 cmp al,bl
1054 jne sd3 ;they do not match....
1055 inc si ;advance pointers
1056 inc di
1057 loop sd8 ;loop for the line lengths
1058 jmp short sd4 ;they match
1059
1060
1061 page
1062
1063;-----------------------------------------------------------------------;
1064; Compare compressing whites and ignoring case differences if
1065; desired too.
1066
1067ib_compare:
1068 mov [ib_first1],true ;we start by the first char in the
1069 mov [ib_first2],true ; in the lines.
1070 pop di ;get pointer to lines
1071 pop si
1072 push si ;re-save pointers
1073 push di
1074sd9:
1075 mov al,byte ptr [si] ;get next char. of first line
1076 call isa_white ;is it a white?
1077 jnc sd12 ;no, compare....
1078sd10:
1079 mov al,byte ptr [si+1] ;peek to next,
1080 call isa_white ; it is a white too?
1081 jnc sd11
1082 inc si ; yes,
1083 jmp short sd10 ; compress all whites to a blank
1084sd11:
1085 cmp [ib_first1],true ;is this the first char. of the line?
1086 jne sd111 ;no, it stays a white
1087 inc si ;ignore the white
1088 jmp short sd12
1089sd111:
1090 cmp al,CR ;is this the last char. of the line
1091 jne sd112 ;no, it stays a white
1092 inc si ;yes, ignore the whites
1093 jmp short sd12
1094sd112:
1095 mov al,' ' ;no more whites found
1096
1097sd12:
1098 cmp [ib_first1],true ;is this the first char. of the line?
1099 jne sd121 ;no, continue
1100 mov [ib_first1],false ;yes, reset the flag
1101sd121:
1102 cmp [flg_c],true ;do we ignore case?
1103 jne sd122 ;no,....
1104 call make_caps
1105sd122:
1106 mov bl,al ;save char
1107 mov al,byte ptr [di] ;get next chra. of second line
1108 call isa_white
1109 jnc sd15
1110sd13:
1111 mov al,byte ptr [di+1] ;peek to next as before
1112 call isa_white
1113 jnc sd14
1114 inc di
1115 jmp short sd13
1116sd14:
1117 cmp [ib_first2],true ;is this the first char. of the line?
1118 jne sd141 ;no, it stays a white
1119 inc di ;ignore the white
1120 jmp short sd15
1121sd141:
1122 cmp al,CR ;is this the last char. of the line
1123 jne sd142 ;no, it stays a white
1124 inc si ;yes, ignore the whites
1125 jmp short sd15
1126sd142:
1127 mov al,' '
1128
1129sd15:
1130 cmp [ib_first2],true ;is this the first char. of the line?
1131 jne sd151 ;no, continue
1132 mov [ib_first2],false ;yes, reset the flag
1133sd151:
1134 cmp [flg_c],true ;do we ignore case?
1135 jne sd152 ;no,....
1136 call make_caps
1137sd152:
1138 cmp al,bl
1139 je sd153
1140 jmp sd3 ;they do not match....
1141sd153:
1142 cmp al,CR ;have we reached the end?
1143 jne sd154 ;no, continue....
1144 jmp sd4 ;yes, they match
1145sd154:
1146 inc si ;no, advance pointers
1147 inc di
1148 jmp sd9 ;loop for the line lengths
1149
1150
1151isa_white:
1152 cmp al,' ' ;is it a space?
1153 je sdx1
1154 cmp al,09h ;is it a tab?
1155 je sdx1
1156 clc ;if not a white return with carry clear
1157 ret
1158sdx1:
1159 stc ;is a white return with carry set
1160 ret
1161
1162
1163 page
1164
1165;-----------------------------------------------------------------------;
1166find_eol:
1167 xor cx,cx ;zero count
1168 cld
1169sd6:
1170 lodsb
1171 cmp al,CR
1172 je sd7
1173 inc cx
1174 jmp short sd6
1175sd7:
1176 ret
1177
1178
1179 subttl Subroutines: adv_b
1180 page
1181
1182;-----------------------------------------------------------------------;
1183; Get the next line in the buffer ;
1184; ;
1185; It will attempt to get the next current line from the buffer ;
1186; if it fails, it will force a refill, and if some data is read in ;
1187; then it will return the next current line. ;
1188; ;
1189; entry: ;
1190; BX pointer to buffer structure ;
1191; ;
1192; exit: ;
1193; SI pointer to next line (if any) ;
1194; Carry set if no more lines available. If carry set then: ;
1195; AX End Code: 0 = end of file reached ;
1196; 1 = no room in buffer for a line ;
1197; ;
1198; modifies: ;
1199; CX,DX and DI ;
1200; ;
1201; Called from txt_compare ;
1202;-----------------------------------------------------------------------;
1203adv_b:
1204 call get_nextl
1205 jc se1
1206 ret
1207se1:
1208 call refill
1209 jnc se0
1210 ret
1211se0:
1212 call get_nextl
1213 ret
1214
1215
1216 subttl Subroutines: get_nextl
1217 page
1218
1219;-----------------------------------------------------------------------;
1220; Returns the next line in a buffer ;
1221; (next from current or next from pointer) ;
1222; ;
1223; entry: ;
1224; BX pointer to buffer structure ;
1225; (SI pointer to line, if calling get_next) ;
1226; ;
1227; exit: ;
1228; SI pointer to next line ;
1229; Carry set if no more lines available ;
1230; ;
1231; modifies: ;
1232; DI and CX ;
1233; ;
1234; Called from adv_b and print_diff (in the case of get_next) ;
1235;-----------------------------------------------------------------------;
1236get_nextl:
1237 mov si,word ptr [bx].curr
1238get_next:
1239 mov cx,word ptr [bx].dat_end
1240 sub cx,si
1241 mov di,si
1242 mov al,LF
1243 cld
1244 repnz scasb
1245 mov si,di ;pointer to next line
1246 jnz se2 ;not found
1247 clc
1248 ret
1249se2:
1250 inc si ;point past the LF
1251 stc
1252 ret
1253
1254
1255 subttl Subroutines: refill
1256 page
1257
1258;-----------------------------------------------------------------------;
1259; Refill a buffer ;
1260; ;
1261; It will refill a buffer with data from the corresponding ;
1262; file. It will first recompact the buffer to make room for the new ;
1263; data. If in SINC then it will move the current line to the top of ;
1264; the buffer, and read the data from the end of this line till the ;
1265; end of the buffer. ;
1266; If NOT in SINC then it will recompact the buffer by moving ;
1267; all lines between the first to go out of SINC till the current line ;
1268; to the top of the buffer, and then reading data after the current ;
1269; line. ;
1270; When recompacting the buffer it relocates all pointers to ;
1271; point to the new locations of the respective lines. ;
1272; Some of the pointers may be pointing to meaningless locations ;
1273; before the relocation, and consecuently they will be pointing to ;
1274; even less meaningfull locations after relocation. ;
1275; After reading the data it normalizes the buffer to make sure ;
1276; that no partially full lines are present at the end of the buffer. If ;
1277; after recompacting and reading some character it is found that the ;
1278; characters read do not constitute a full line, then it will return ;
1279; with an error code. It will also return with an error code if it ;
1280; attempts to read past the end of file. ;
1281; ;
1282; entry: ;
1283; BX pointer to buffer structure ;
1284; ;
1285; exit: ;
1286; Carry set if no chars read into the buffer. If carry set then: ;
1287; AX End Code: 0 = end of file reached ;
1288; 1 = no room in the buffer for a line ;
1289; ;
1290; modifies: ;
1291; CX,DX,SI and DI ;
1292; ;
1293; Called from adv_b ;
1294;-----------------------------------------------------------------------;
1295refill:
1296
1297;----- Calculate ammount to move & pointer relocation factor.
1298
1299 cmp [sinc],true
1300 jne sf1
1301 mov si,word ptr [bx].curr
1302 jmp short sf2
1303sf1:
1304 mov si,word ptr [bx].fst_nosinc
1305sf2:
1306 mov di,word ptr [bx].buf
1307 mov cx,word ptr [bx].dat_end
1308
1309 mov dx,si ;calculate pointer relocation factor
1310 sub dx,di ;DX = factor
1311 jz sf3 ;no room in buffer
1312 sub cx,si ;calculate ammount of data to move
1313 inc cx ;CX = ammount
1314
1315;----- Move data
1316
1317 cld ;auto decrement
1318 rep movsb
1319
1320;----- Relocate pointers
1321
1322 sub word ptr [bx].curr,dx
1323 sub word ptr [bx].lst_curr,dx
1324 sub word ptr [bx].fst_sinc,dx
1325 sub word ptr [bx].fst_nosinc,dx
1326 sub word ptr [bx].dat_end,dx
1327
1328sf3:
1329 mov dx,word ptr [bx].dat_end
1330 inc dx ;empty part starts here
1331
1332;----- fill the buffer
1333
1334 call fill_buffer
1335 ret
1336
1337
1338 subttl Subroutines: fill_buffer
1339 page
1340
1341;-----------------------------------------------------------------------;
1342; Fill the data buffers ;
1343; ;
1344; It will fill the buffer from the pointer to the end of buffer ;
1345; and normalize the buffer. ;
1346; ;
1347; entry: ;
1348; BX pointer to buffer structure ;
1349; DX pointer to buffer (or part of buffer) ;
1350; ;
1351; exit: ;
1352; Carry set if no chars read into the buffer. If carry set then: ;
1353; AX End Code: 0 = end of file reached ;
1354; 1 = no room in the buffer for a line ;
1355; ;
1356; modifies: ;
1357; AX,CX,DX and DI ;
1358; ;
1359; Called from txt_compare and refill ;
1360;-----------------------------------------------------------------------;
1361fill_buffer:
1362 push bx
1363 call read_dat ;get data
1364 jc bad_read
1365 or ax,ax ;zero chars read?
1366 jz rd_past_eof
1367 call nor_buf
1368 mov di,cx ;save normalized char. count
1369 mov bp,dx ;save data end for now
1370
1371;----- seek for old partial line
1372
1373 or ax,ax ;is the seek value = 0 ?
1374 jz sg1 ;yes, do not seek
1375 mov dx,ax
1376 neg dx
1377 mov cx,-1
1378 mov al,1 ;seek from current position
1379 mov ah,lseek
1380 int 21h
1381 jc bad_read ;error mesage (BX already in stack)
1382
1383sg1:
1384 mov cx,di ;restore normalized char count.
1385 or cx,cx ;char count = 0 due to normalization?
1386 jz no_room
1387
1388 pop bx
1389 mov word ptr [bx].dat_end,bp
1390 clc
1391 ret
1392
1393bad_read:
1394 mov dx,offset dg:read_err_pre
1395 mov cl,read_err_pre_len
1396 call prt_err ;print error message
1397 pop bx
1398 mov dx,word ptr[bx].fname
1399 mov cx,word ptr[bx].fname_len
1400 call prt_err ;print file name
1401 mov dx,offset dg:read_err_post
1402 mov cl,read_err_post_len
1403 jmp an_err
1404
1405no_room:
1406 mov ax,1
1407 jmp short sg2
1408
1409rd_past_eof:
1410 xor ax,ax
1411sg2:
1412 pop bx
1413 stc
1414 ret
1415
1416
1417 subttl Subroutines: read_dat
1418 page
1419
1420;-----------------------------------------------------------------------;
1421; ;
1422; entry: ;
1423; DX pointer to data area (buffer or part of buffer) ;
1424; ;
1425; exit: ;
1426; AX character count or error code (from DOS read) ;
1427; Carry set if error condition ;
1428; ;
1429; modifies: ;
1430; BX and CX ;
1431; ;
1432; Called from fill_buffer, print_all and bin_compare ;
1433;-----------------------------------------------------------------------;
1434read_dat:
1435 mov cx,word ptr [bx].buf_end
1436 mov bx,word ptr [bx].handle
1437 sub cx,dx ;ammount to read to buff1
1438 mov ah,read
1439 int 21h
1440 ret
1441
1442
1443 subttl Subroutines: nor_buf
1444 page
1445
1446;-----------------------------------------------------------------------;
1447; Normalize buffers so they do not have partially full ;
1448; lines at the end. If character count is less than the buffer size ;
1449; then it checks that the last line is terminated by a CR,LF pair. ;
1450; If it is not it inserts a CR,LF at the end. It returns a seek value ;
1451; for the buffer corresponding to the number of characters in the ;
1452; incomplete line at the end of the buffer (if any). This can be used ;
1453; to start reading from the beggining of the incomplete line on next ;
1454; time the buffer is loaded. ;
1455; ;
1456; ENTRY: ;
1457; DX buffer pointer ;
1458; AX character count read ;
1459; CX character count requested ;
1460; ;
1461; EXIT: ;
1462; DX pointer to last char in buffer (normalized) ;
1463; CX character count (normalized) ;
1464; AX seek value ;
1465; ;
1466; MODIFIES: ;
1467; DI ;
1468; ;
1469; Called from fill_buffer ;
1470;-----------------------------------------------------------------------;
1471nor_buf:
1472 mov di,dx
1473 add di,ax
1474 dec di ;points to last char in buffer
1475 cmp ax,cx ;were all chars. requested read?
1476 je sm7 ;yes, buffer full
1477 cmp byte ptr[di],1ah ;terminated with a ^Z ?
1478 jne sm1
1479 dec di ;point to previous character
1480 dec ax ;decrement character count
1481sm1: cmp byte ptr[di],lf ;is last char a LF?
1482 je sm6
1483 cmp byte ptr[di],cr ;is it a CR then?
1484 je sm5
1485 add ax,2 ;two more chars in buffer
1486 inc di
1487sm2: mov byte ptr[di],cr
1488sm3: inc di
1489 mov byte ptr[di],lf
1490sm4: mov cx,ax ;new character count
1491 mov dx,di ;pointer to last char
1492 xor ax,ax ;seek = 0
1493 ret
1494
1495sm5:
1496 inc ax ;one more char in buffer
1497 jmp short sm3
1498
1499sm6:
1500 cmp byte ptr[di-1],cr ;is previous char a CR?
1501 je sm4
1502 inc ax ;no, one more char in buffer
1503 jmp short sm2
1504
1505sm7:
1506 push ax ;save char count
1507 mov cx,ax
1508 mov al,LF
1509 std
1510 repnz scasb ;search for last LF
1511 pop ax ;restore char count
1512 jnz bad_line ;none found, line too big
1513 inc di ;point to last LF
1514 mov dx,di
1515 inc cx ;ammount of chars in buffer
1516 sub ax,cx ;seek value
1517 ret
1518
1519bad_line: ;full line not possible, return
1520 mov dx,di ; with AX=count, CX=0 and DX=
1521 ret ; old last char in buffer pointer.
1522
1523
1524
1525 subttl Subroutines: print_diff
1526 page
1527
1528;-----------------------------------------------------------------------;
1529; print the difference between buffers ;
1530; ;
1531; It will print the mismatched lines. First it prints a heading ;
1532; with the first file name, then the lines that differ from file 1, ;
1533; then a heading with the second file name, and then the lines that ;
1534; differ in file 2 . ;
1535; The lines that differ are considered to start from fst_nosinc ;
1536; till fst_sinc. ;
1537; ;
1538; Called from txt_compare ;
1539;-----------------------------------------------------------------------;
1540print_diff:
1541 mov bx,offset dg:buf1
1542 call print_head ;print heading for file 1
1543 mov dx,word ptr [bx].fst_nosinc
1544 mov si,word ptr [bx].fst_sinc
1545 call get_next ;get pointer to next line
1546 mov cx,si
1547 sub cx,dx ;get character count
1548 call prout
1549 mov bx,offset dg:buf2
1550 call print_head ;print heading for file 1
1551 mov dx,word ptr [bx].fst_nosinc
1552 mov si,word ptr [bx].fst_sinc
1553 call get_next ;get pointer to next line
1554 mov cx,si
1555 sub cx,dx ;get character count
1556 call prout
1557 mov dx,offset dg:diff_sep
1558 mov cl,diff_sep_len
1559 xor ch,ch
1560 call prout ;print difference separator
1561 ret
1562
1563
1564 subttl Subroutines: print_head
1565 page
1566
1567;-----------------------------------------------------------------------;
1568; Print heading for difference ;
1569; ;
1570; entry: ;
1571; BX pointer to buffer structure ;
1572; ;
1573; modifies: ;
1574; AX,CX and DX ;
1575; ;
1576; Called from txt_compare and print_diff ;
1577;-----------------------------------------------------------------------;
1578print_head:
1579 mov dx,offset dg:fname_sep
1580 mov cl,fname_sep_len
1581 xor ch,ch
1582 call prout
1583 mov dx,word ptr [bx].fname
1584 mov cx,word ptr [bx].fname_len
1585 call prout
1586 mov dx,offset dg:CRLF
1587 mov cx,2
1588 call prout
1589 ret
1590
1591
1592 subttl Subroutines: print_all
1593 page
1594
1595;-----------------------------------------------------------------------;
1596; Print the rest of a file ;
1597; ;
1598; If in SINC it will print the file from the fst_nosinc line ;
1599; till the end of the file. If NOT in SINC then it will print from ;
1600; the current line of the buffer to the end of the file. ;
1601; ;
1602; entry: ;
1603; BX pointer to buffer structure ;
1604; ;
1605; modifies: ;
1606; AX,CX and DX ;
1607; ;
1608; Called from txt_compare ;
1609;-----------------------------------------------------------------------;
1610print_all:
1611 cmp [sinc],true ;are we in SINC?
1612 jne so1
1613 mov dx,word ptr [bx].curr
1614 jmp short so2
1615so1:
1616 mov dx,word ptr [bx].fst_nosinc
1617so2:
1618 mov cx,word ptr [bx].dat_end
1619 inc cx
1620
1621prt_again:
1622 sub cx,dx ;ammount of data to write
1623 call prout ;write it out
1624
1625;----- Read more data to the buffer
1626 push bx ;save pointer to buffer struct
1627 mov dx,word ptr [bx].buf
1628 call read_dat
1629 jnc so3
1630 jmp bad_read ;print error (BX in stack)
1631so3:
1632 or ax,ax ;zero chars read?
1633 jne so4
1634 pop bx ;all done writting
1635 ret
1636so4:
1637 pop bx
1638 mov cx,word ptr [bx].buf_end
1639 jmp short prt_again ;print next buffer full
1640
1641
1642 subttl Subroutines: prout and prt_err
1643 page
1644
1645;-----------------------------------------------------------------------;
1646; ;
1647;-----------------------------------------------------------------------;
1648prout:
1649 push bx
1650 mov bx,stdout
1651 mov ah,write
1652 int 21h
1653 pop bx
1654 ret
1655
1656
1657;-----------------------------------------------------------------------;
1658; ;
1659;-----------------------------------------------------------------------;
1660prt_err:
1661 push bx
1662 xor ch,ch
1663 jcxz retpbx
1664 mov bx,stderr
1665 mov ah,write
1666 int 21h
1667retpbx:
1668 pop bx
1669 ret
1670
1671code ends
1672
1673 page
1674
1675
1676stack segment stack
1677
1678 dw 128 dup(?)
1679
1680stack ends
1681
1682
1683 end start
1684