summaryrefslogtreecommitdiff
path: root/v2.0/source/FC.ASM
blob: 21ed991fc578e087e87c89bf1831a5edf23e367d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
        title   File Compare Routine for MSDOS 2.0

;-----------------------------------------------------------------------;
; Revision History:                                                     ;
;                                                                       ;
; V1.0  Rev. 0  10/27/82        M.A.Ulloa                               ;
;                                                                       ;
;       Rev. 1  10/28/82        M.A.Ulloa                               ;
;         Changed switch names and added binary compare using the       ;
;       -b switch.                                                      ;
;                                                                       ;
;       Rev. 1  11/4/82         A.R. Reynolds                           ;
;         Messages in separate module                                   ;
;       Also added header for MSVER                                     ;
;                                                                       ;
;       Rev. 2  11/29/82        M.A. Ulloa                              ;
;         Corrected sysntex problem with references to [base...]        ;
;                                                                       ;
;       Rev. 3  01/03/83        M.A. Ulloa                              ;
;         Stack is right size now.                                      ;
;                                                                       ;
;-----------------------------------------------------------------------;

FALSE   equ     0
TRUE    equ     0ffh


buf_size equ    4096                    ;buffer size


;-----------------------------------------------------------------------;
;               Description                                             ;
;                                                                       ;
;       FC [-# -b -w -c] <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