summaryrefslogtreecommitdiff
path: root/v4.0/src/CMD/FASTOPEN/FASTOPEN.ASM
blob: 5594abd8c31dd10b85fbf50c127680f861edb843 (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
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
	Page 84,132 ;
Title	FASTOPEN
;Date: May 13,1988
;==============================================================================
;		 EQUATES
;==============================================================================
Is_drive_head	   EQU	   00000001b								   ;AN000;
Is_delete	   EQU	   00000010b								   ;AN000;
Is_insert	   EQU	   00000100b								   ;AN000;
Not_drive_head	   EQU	   11111110b								   ;AN000;
Not_delete	   EQU	   11111101b								   ;AN000;
Not_insert	   EQU	   11111011b

EMS_SAVE_STATE	   EQU	   4FH									   ;AN000;
EMS_RESTORE_STATE  EQU	   4FH									   ;AN000;
EMS_INT 	   EQU	   67H									   ;AN000;
DOS_PAGE1	   EQU	   0FEH 								   ;AN000;


;==============================================================================
;		   INCLUDE  FILES
;==============================================================================
.xcref
.xlist
debug=0 		   ; an equate only for DOSMAC.inc				     ;AN000;
INCLUDE  DOSMAC.inc										    ;AN000;
.list
.cref
INCLUDE  dirent.inc										    ;AN000;
INCLUDE  fastsegs.inc	   ; this cannot include in Fastopen.inc
INCLUDE  fastopen.inc	   ; this include file also contains DOS equates			    ;AN000;
include  version.inc

;==============================================================================



EXTRN	FK_OPEN:FAR										   ;AN000;
EXTRN	FK_CLOSE:FAR										   ;AN000;
EXTRN	FK_INSERT:FAR										   ;AN000;
EXTRN	FK_DELETE:FAR										   ;AN000;
EXTRN	FK_LOOKUP:FAR										   ;AN000;
EXTRN	FK_TRUNCATE:FAR 									   ;AN000;
EXTRN	FK_PURGE:FAR										;AN000;


;============================================================================

CSEG_MAIN   SEGMENT   PARA   PUBLIC 'code'
	ASSUME	cs:cseg_main, ds:nothing,es:nothing,ss:nothing
;============================================================================

PUBLIC	MAIN											   ;AN000;

IF	BUFFERFLAG
PUBLIC	SAVE_EMS_PAGE_STATE
PUBLIC	EMS_PAGE_NUMBER
ENDIF

PUBLIC	RESTORE_PAGE_STATE
PUBLIC	EMS_SAVE_HANDLE1

PUBLIC	Main_name_cache_seg									   ;AN000;
PUBLIC	Main_Num_Of_drives									   ;AN000;
PUBLIC	Main_Ext_Count										   ;AN000;
PUBLIC	Main_extent_drive_Buff									   ;AN000;
PUBLIC	Main_ext_cache_size									   ;AN000;
PUBLIC	Main_name_cache_Buff									   ;AN000;
PUBLIC	Main_EMS_FLAG										   ;AN000;
PUBLIC	Main_Res_Segs										   ;AN000;
PUBLIC	Main_EMS_PAGE_SIZE									   ;AN000;
PUBLIC	Main_EMS_PAGE_SEG									   ;AN000;
PUBLIC	Main_Total_Ext_Count									   ;AN000;
PUBLIC	Main_Total_Name_Count									   ;AN000;
PUBLIC	Main_Name_Drive_Buff									   ;AN000;
PUBLIC	Main_ParamBuff										   ;AN000;

PUBLIC	FOPEN_Insert										   ;AN000;
PUBLIC	FOPEN_Update										   ;AN000;
PUBLIC	FOPEN_Delete										   ;AN000;
PUBLIC	FOPEN_Lookup										   ;AN000;
PUBLIC	FOPEN_PURGE										  ;AN000;

PUBLIC	FSEEK_Open										   ;AN000;
PUBLIC	FSEEK_Close										   ;AN000;
PUBLIC	FSEEK_Insert										   ;AN000;
PUBLIC	FSEEK_Delete										   ;AN000;
PUBLIC	FSEEK_Lookup										   ;AN000;
PUBLIC	FSEEK_Truncate										   ;AN000;
PUBLIC	FSEEK_Purge										   ;AN000;

PUBLIC	 VECTOR_LookUp										  ;AN000;
PUBLIC	 VECTOR_Delete										  ;AN000;


; Following data variables are accessed by all other segments
call_cnt	       DW    0									;AN000;
Purge_Flag	       DW    0		   ; =1 if last call is PURGE function
Prev_drv_id	       DB    -1 	   ; previous request drive id
Main_name_cache_seg    DW    Cseg_Init	   ; default to Init1 seg				;AN000;
Main_Num_Of_drives     DW    0		   ; number of drives					;AN000;
Main_Ext_Count	       DW    0		   ; total name extent entries				;AN000;
Main_extent_drive_Buff DW    0		   ; addrs to extent drive				  ;AN000;
Main_name_cache_Buff   DW    0		   ; address of Name cache buffer			;AN000;
Main_ext_cache_size    DW    0		   ; extent cache size
Main_EMS_FLAG	       DW    0		   ; EMI flag  1= if EMI is enabled			;AN000;
Main_Res_Segs	       DW    0		   ; number of segs to be stay resident 		;AN000;
Main_Total_Ext_Count   DW    0		   ; Total extent count entries 			;AN000;
Main_Total_Name_Count  DW    0		   ; Total name count entries				;AN000;
Main_Name_Drive_Buff   DW    0		   ; EMS data page segment ID				;AN000;
Main_ParamBuff	       DW    50  dup (0)   ; Drive ID/extent count buffer			;AN000;

; The following structure is for saving and restoring EMS page state
EMS_PAGE_MAP	     LABEL    WORD
Main_EMS_SEG_COUNT     DW    1		   ; EMS segment count
Main_EMS_PAGE_SEG      DW    0		   ; EMS page segment ID				;AN000;


Main_EMS_PAGE_SIZE     DW    0		   ; EMS page size					;AN000;
EMS_PAGE_ARRAY	       DW  30	dup  (0)   ; EMS state save array

; The following data values are used by MAIN segment
EMS_SAVE_LOG_PAGE1     DW    ?		   ;HOLDS PREVIOUS PAGE1				    ;AN000;
EMS_SAVE_HANDLE1       DW    ?		   ;HOLDS PREVIOUS handle1				    ;AN000;

IF	BUFFERFLAG
;----------------------------------------------------------HKN 8/26/88

EMS_PAGE_NUMBER		DW	?			; holds the ems 
							; physical page no.

ENDIF
;
;-----------------------------------------------------------------------------
;	  Fastopen/Fastseek function jump vectors
; Inititally the jump vectors have default offset and segment values.
; If the modules are relocated, the offset and the segID in the jump vectors
; may be changed to the new segID of the new location.
;-----------------------------------------------------------------------------
FOPEN_Insert	 DD   Insert									 ;AN000;
FOPEN_Update	 DD   Update									 ;AN000;
FOPEN_Delete	 DD   delete									 ;AN000;
FOPEN_Lookup	 DD   lookup									 ;AN000;
FOPEN_Purge	 DD   FP_purge									 ;AN000;

FSEEK_Open	 DD   Fk_Open									 ;AN000;
FSEEK_Close	 DD   Fk_Close									 ;AN000;
FSEEK_Insert	 DD   Fk_Insert 								 ;AN000;
FSEEK_Delete	 DD   Fk_Delete 								 ;AN000;
FSEEK_Lookup	 DD   Fk_Lookup 								 ;AN000;
FSEEK_Truncate	 DD   Fk_Truncate								 ;AN000;
FSEEK_Purge	 DD   Fk_Purge									 ;AN000;

VECTOR_LookUp	 DD   LookUp	      ; jump vector to LookUp used by Insert call
VECTOR_Delete	 DD   Fk_Delete       ; jump vector to Delete used by Free_buffer routine





;==============================================================================

MAIN	PROC	FAR			  ; FAR procedure for FAR call from DOS
	push	cx			  ; save DOS registers				     ;AN000;
	push	dx			  ; makesure to restore the necessary			   ;AN000;
	push	ds			  ; ones on return					  ;AN000;
	push	es										   ;AN000;
	push	bp										   ;AN000;
	push	di										   ;AN000;
	push	bx										   ;AN000;

;-----------------------------------------------------------------------------
; The cache buffers are maintained in a seperate segement whose segment ID is
; in Name_Cache_Seg.  The ES will be used as the seg register during the access
; of data in the cache buffers, while DS will be used to access the Fastopen
; resident and non-resident data area.
;-----------------------------------------------------------------------------
	cmp	cs:Main_EMS_flag,1	  ; EMS enabled ??					     ;AN000;
	jne	dispatch_funcs		  ; no - dispatch functions			   ;AN000;
					  ; yes - save EMS page state
IF	NOT BUFFERFLAG

;-----------------------------------------------------------------------------
; SAVE EMS PAGE STATE
;-----------------------------------------------------------------------------
	PUSH	AX			  ; save registers
	PUSH	CX
	PUSH	DX										   ;AN000;
	PUSH	DS										   ;AN000;
	PUSH	ES										   ;AN000;
	PUSH	BP										   ;AN000;
	PUSH	SI										   ;AN000;
	PUSH	DI										   ;AN000;
	PUSH	BX										   ;AN000;
	MOV	AX, SEG EMS_PAGE_MAP	  ; get segid
	MOV	DS,AX
	LEA	SI,EMS_PAGE_MAP 	  ; DS:SI-->page map struc
	MOV	AX, SEG EMS_PAGE_ARRAY	  ; get segid
	MOV	ES,AX
	LEA	DI,EMS_PAGE_ARRAY	  ; ES:DI-->Page ARRAY
	MOV	AH,EMS_SAVE_STATE	  ;
	MOV	AL,0			  ; subfunction code
	INT	EMS_INT 		  ; save page state							    ;AN000;

	POP	BX										   ;AN000;
	POP	DI										   ;AN000;
	POP	SI										   ;AN000;
	POP	BP										   ;AN000;
	POP	ES										   ;AN000;
	POP	DS										   ;AN000;
	POP	DX										   ;AN000;
	POP	CX										   ;AN000;

	CMP	AH,0			 ; save ok??
	JNE	SAVE_FAILED		 ; no, error
	POP	AX			 ; clear stack

ELSE


;------------------------------------------------------------HKN 8/26/88--
;	Before dispatching off the fastopen functions we must do the 
;	following:
;		1. save the map for this page
;		2. map this page to log. page 0 with the fastopen handle in
;		   ems_save_handle1.
;		3. dispatch
;

;	int	3

	push	ax
	push	cx
	push	dx
	push	ds
	push	es
	push	bp
	push	si
	push	di
	push	bx

	call	far ptr	save_ems_page_state
	jc	ems_failed

	call	map_page
	jc	ems_failed

	pop	bx
	pop	di
	pop	si
	pop	bp
	pop	es
	pop	ds
	pop	dx
	pop	cx
	POP	AX			 ; restore registers

	JMP	DISPATCH_FUNCS		 ; yes, dispatch functions

EMS_FAILED:
	pop	bx
	pop	di
	pop	si
	pop	bp
	pop	es
	pop	ds
	pop	dx
	pop	cx

ENDIF

IF	NOT BUFFERFLAG
SAVE_FAILED:
ENDIF

	POP	AX			 ; restore registers

	POP	BX			 ; no, restore DOS registers 				   ;AN000;
	POP	DI										   ;AN000;
	POP	BP										   ;AN000;
	POP	ES										   ;AN000;
	POP	DS										   ;AN000;
	POP	DX										   ;AN000;
	POP	CX										   ;AN000;
	STC
	JMP	ERROR_RET		 ; error return


;-----------------------------------------------------------------------------
; FASTOPEN/FASTSEEK DISPATCHER
;-----------------------------------------------------------------------------
DISPATCH_FUNCS:
	cmp	al,5		      ; buffer purge ??
	je	Check_Drive_id	      ; yes - check drive id
	cmp	al,11		      ; Fastopen function call ??				   ;AN000;
	jge	Check_drive_id	      ; no - dispatch Fastseek functions
	jmp	Dispatch_fopen	      ; yes - dispatch Fastopen functions						 ;AN000;


;-----------------------------------------------------------------------------
; Check to see the Drive ID in DL is the valid. If not error and return DI=1
; if Fastseek LookUp function. Makesure to preserve AL, DS, SI and DI
;-----------------------------------------------------------------------------
CHECK_DRIVE_ID:
	cmp	cs:Prev_drv_id, dl	    ; current id same as previous valid
	je	Dispatch_Fseek		    ; yes - dont check drive ID

	push	si										   ;AN000;
	push	bx			    ;DS=addressability to Cseg_Main			   ;AN000;
	push	cx										   ;AN000;
	lea	si,cs:Main_ParamBuff	    ; DS:SI-->drive ID buffer				   ;AN000;
	mov	cx,cs:Main_Num_Of_Drives    ; number of drives					   ;AN000;

Get_Drive_Id:											   ;AN000;
	mov	bx,cs:[si]									   ;AN000;
	cmp	bl,dl			    ; drive ID match ?? 				   ;AN000;
	je	drive_found		    ; yes, drive ID found				   ;AN000;
	add	si,4			    ; (2/11) no, move pointer to next ID			  ;AN000;
	LOOP	get_drive_id		    ; check next drive id				   ;AN000;

Drive_Not_Found:			    ; drive id not found
	pop	cx			    ; restore registers 			       ;AN000;
	pop	bx										   ;AN000;
	pop	si										   ;AN000;
	jmp	Error_Exit		    ; return

Drive_Found:				    ; drive ID found
	mov	cs:Prev_drv_id,dl	    ; save drive id as prev drive id
	pop	cx			    ; restore registers 				   ;AN000;
	pop	bx			    ; and do the specified function		      ;AN000;
	pop	si										   ;AN000;

;-----------------------------------------------------------------------------
;     FASTSEEK FUNCTION DISPATCHER
;-----------------------------------------------------------------------------
DISPATCH_FSEEK:
	cmp	al,010H
	jle	Fsk_Cont
	inc	cs:call_cnt									   ;AN000;
;	cmp	cs:call_cnt,0efffH	   ; for debugging
;	jne	 fsk_cont		   ; for debugging


Fsk_Cont:
	push	cs			   ; set addressability
	pop	ds			   ; CS = DS = Cseg_Main segment
	ASSUME	ds:Cseg_Main
	cmp	al,FONC_Purge		   ; PURGE call ??					       ;AN000;
	je	chk_05			   ; yes - continue						;AN000;

	mov	cs:Purge_Flag, 0	   ; reset purge flag
	cmp	al,FSK_Open		   ; OPEN call							;AN000;
	jne	chk_12			   ; jump if not						;AN000;
	CALL	FSEEK_OPEN										;AN000;
	jmp	exit											;AN000;
Chk_12:
	cmp	al,FSK_Close		   ; CLOSE ??							;AN000;
	jne	chk_14											;AN000;
	CALL	FSEEK_CLOSE		   ; process close function					;AN000;
	jmp	exit											;AN000;
Chk_14:
	cmp	al,FSK_Lookup		   ; LOOKUP ??							;AN000;
	jne	chk_15											;AN000;
	CALL	FSEEK_LOOKUP		   ; process lookup						;AN000;
	CALL	RESTORE_PAGE_STATE	   ; restore EMS page						;AN000;
	pop	dx			   ; dont restore original BX and DI				;AN000;
	pop	dx			   ; from DOS since BX and DI contins return values	   ;AN000;
	jmp	exit_1			   ; exit

Chk_15:
	cmp	al,FSK_Insert		   ; INSERT ??							;AN000;
	jne	chk_13											;AN000;
	CALL	FSEEK_INSERT		   ; Process insert						;AN000;
	jmp	exit											;AN000;
Chk_13:
	cmp	al,FSK_DELETE		   ; DELETE ??							;AN000;
	jne	chk_16											;AN000;
	CALL	FSEEK_DELETE		   ; process delete						;AN000;
	jmp	short  exit										       ;AN000;
Chk_16:
	cmp	al,FSK_Trunc		   ; TRUNCATE ??						;AN000;
	jne	Chk_05			   ;
	CALL	FSEEK_TRUNCATE		   ; process truncate						;AN000;
	jmp	short exit										      ;AN000;

Chk_05:
	cmp	cs:Purge_Flag, 1	   ; previous call is purge ??				    ;AN000;
	jne	Purge_buffs		   ; no - purge the buffers
	clc				   ; yes - exit
	jmp	short exit										      ;AN000;

Purge_Buffs:
	mov	cs:Purge_Flag,1 	   ; set purge flag
	cmp	CS:Main_Total_Ext_Count,0	    ; reset fseek buffs??
	je	reset_fopen		   ; no - reset fopen
	CALL	FSEEK_PURGE		   ; reset extent cache 			    ;AN000;

Reset_Fopen:
	cmp	CS:Main_Total_Name_Count,0	    ; reset fopen buffs??
	je	Reset_Exit		   ; no - reset f
	CALL	CS:FOPEN_PURGE		      ; reset extent cache			       ;AN000;

Reset_Exit:
	clc
	jmp	short exit										 ;AN000;


; NOTE: Carry Flag state from Function calls must be correctly returned
;	to the DOS, especially from Fastseek Lookup function


;-----------------------------------------------------------------------------
;	FASTOPEN FUNCTION DISPATCHER
;-----------------------------------------------------------------------------
DISPATCH_FOPEN: 		      ; dispatch FOPEN functions
	cld											   ;AN000;
	mov	cs:Purge_Flag, 0      ; reset purge flag
	cmp	al, FONC_update 								   ;AN000;
	jne	Chk_02										   ;AN000;
	CALL	CS:Fopen_Update       ; UPDATE							   ;AN000;
	jmp	short exit										 ;AN000;

Chk_02:
	cmp	al, FONC_insert 								   ;AN000;
	jne	Chk_01										   ;AN000;
	CALL	CS:Fopen_Insert       ; INSERT							   ;AN000;
	jmp	short exit										 ;AN000;
Chk_01:
	cmp	al, FONC_look_up								   ;AN000;
	jne	chk_03										   ;AN000;
	CALL	CS:Fopen_lookup       ; LOOKUP							   ;AN000;
	jmp	short exit										 ;AN000;
Chk_03:
	cmp	al, FONC_delete 								   ;AN000;
	jne	Error_Exit									   ;AN000;
	CALL	CS:Fopen_delete       ; DELETE							   ;AN000;
	jmp	short exit										 ;AN000;



;-----------------------------------------------------------------------------
;  EXIT TO DOS FROM FUNCTIONS
;-----------------------------------------------------------------------------

ERROR_EXIT:	     ; EXIT from invalid drive id search loop
	CALL	RESTORE_PAGE_STATE     ; restore frame buff status				   ;AN000;
				       ; on return AX should have function code
	pop	bx		       ; restore first two regs of DOS
	pop	di										   ;AN000;
	cmp	al,FSK_Lookup									   ;AN000;
	jne	exit_2										   ;AN000;
	mov	di,1		       ; set error flag - invalid drive id			   ;AN000;
	stc											   ;AN000;
	jmp	short Exit_1									   ;AN000;

EXIT_2:
	clc											   ;AN000;
	jmp	short Exit_1									   ;AN000;


; Normal Exit from Fastopen Functions except Fastseek Lookup function
EXIT:
	CALL	RESTORE_PAGE_STATE     ; restore EMS page state 				   ;AN000;;AN000;
	pop	bx		       ; restore BX						   ;AN000;
	pop	di		       ; restore DI						   ;AN000;


; Exit from FastSeek Lookup function. Dont restore BX and DI
EXIT_1:
	pop	bp		       ; restore remaining DOS registers
	pop	es		       ; except BX and DI since they contain								;AN000;
	pop	ds		       ; return values. 					    ;AN000;
	pop	dx										   ;AN000;
	pop	cx										   ;AN000;

ERROR_RET:
	ret											   ;AN000;

MAIN	ENDP

IF	BUFFERFLAG
;---------------------------------------------------------------------------
;	Procedure name	:	save_ems_page_state
;	
;	Description:
;		Saves the state of the page whose physical segment value is
;	specified in Main_EMS_PAGE_SEG. 
;---------------------------------------------------------------------------

SAVE_EMS_PAGE_STATE	PROC	FAR

	PUSH	AX			  ; save registers
	PUSH	CX
	PUSH	DX										   ;AN000;
	PUSH	DS										   ;AN000;
	PUSH	ES										   ;AN000;
	PUSH	BP										   ;AN000;
	PUSH	SI										   ;AN000;
	PUSH	DI										   ;AN000;
	PUSH	BX										   ;AN000;

	MOV	AX, SEG EMS_PAGE_MAP	  ; get segid
	MOV	DS,AX
	LEA	SI,EMS_PAGE_MAP 	  ; DS:SI-->page map struc
	MOV	AX, SEG EMS_PAGE_ARRAY	  ; get segid
	MOV	ES,AX
	LEA	DI,EMS_PAGE_ARRAY	  ; ES:DI-->Page ARRAY
	MOV	AH,EMS_SAVE_STATE	  ;
	MOV	AL,0			  ; subfunction code
	INT	EMS_INT 		  ; save page state							    ;AN000;

	POP	BX										   ;AN000;
	POP	DI										   ;AN000;
	POP	SI										   ;AN000;
	POP	BP										   ;AN000;
	POP	ES										   ;AN000;
	POP	DS										   ;AN000;
	POP	DX										   ;AN000;
	POP	CX										   ;AN000;

	CMP	AH,0			 ; save ok??
	JE	SAVE_OK			 ; 
	STC
	JMP	SHORT DONE
SAVE_OK:
	CLC
DONE:
	POP	AX
	RET

SAVE_EMS_PAGE_STATE	ENDP

ENDIF


;-----------------------------------------------------------------------------
; PROCERDURE:  RESTORE_PAGE_STATE
;
; Function:    Restore state of EMS page
;
; Input:       None
; Output:      Page is restored
;
;-----------------------------------------------------------------------------

RESTORE_PAGE_STATE    PROC  NEAR	;RESTORE EMS PAGE STATE
	PUSHF				;save flag					     ;AN000;
	CMP	CS:MAIN_EMS_FLAG, 0	;EMS enabled ?? 					   ;AN000;
	JNE	REST_PUSH_REGS		;yes, restore registers
	JMP	SHORT RESTORE_EXIT	;no, exit						   ;AN000;
					;yes, restore page registers
REST_PUSH_REGS:
	PUSH	AX			; save function code
	PUSH	CX			; save caller registers 				    ;AN000;
	PUSH	DX										   ;AN000;
	PUSH	DS										   ;AN000;
	PUSH	ES										   ;AN000;
	PUSH	BP										   ;AN000;
	PUSH	SI										   ;AN000;
	PUSH	DI										   ;AN000;
	PUSH	BX										   ;AN000;

	MOV	AX, SEG EMS_PAGE_ARRAY
	MOV	DS,AX
	LEA	SI,EMS_PAGE_ARRAY	; DS:SI-->Page array
	MOV	AH,EMS_RESTORE_STATE	;
	MOV	AL,1			;
	INT	EMS_INT 		; restre page state							      ;AN000;
	CMP	AH,0			; restore OK ??
	JE	REST_POP_REGS		; yes
	STC				; set carry

REST_POP_REGS:
	POP	BX			; RESTORE REGISTERS					   ;AN000;
	POP	DI										   ;AN000;
	POP	SI										   ;AN000;
	POP	BP										   ;AN000;
	POP	ES										   ;AN000;
	POP	DS										   ;AN000;
	POP	DX										   ;AN000;
	POP	CX										   ;AN000;
	POP	AX			; restore function code

RESTORE_EXIT:
	POPF
	RET											   ;AN000;

RESTORE_PAGE_STATE    ENDP


IF	BUFFERFLAG

;---------------------------------------------------------HKN 8/26/88-------
;	procedure name		:	map_page
;	Inputs			: 	ems_page_number = physical page frame
;							  number.
;					ems_save_handle1 = emm_handle.
;	Output			: 	CY - error
;					NC - page is mapped to logical page 0
;----------------------------------------------------------------------------
map_page	proc	near

	push	ax
	push	bx
	push	dx

	xor	bx, bx
	mov	ax, cs:ems_page_number	; contains the page number obtained 
					; during fastopen intialization.
	mov	ah, 44h
	mov	dx, cs:ems_save_handle1	; contains the emm handle that was
					; obtained during fast init.
	int	ems_int
	or	ah, ah
	jnz	err_map_page
	clc
	jmp	short map_page_done

err_map_page:
	stc

map_page_done:
	pop	dx
	pop	bx
	pop	ax
	ret

map_page	endp

ENDIF
	
	
					 ; NOTE:
CSEG_MAIN   ENDS			 ; End of the first portion of the
					 ; Cseg_Main segment.  Remaining
					 ; portion is in Fastinit.asm

;-----------------------------------------------------------------------------





;==============================================================================
; All Fastopen functions are kept in a seperate segment.  These are accessed
; by a FAR indirect call from the MAIN routine.
; ADDRESSABILTY: CS is used for accessing local data in Cseg_Open segment
;		 DS is used for accessing data in the drive cache buffer
;					  in the Cseg_Init segment
;		 ES is used for accessing data in the name cache buffer
;					  in the Cseg_Init segment
;
;*****************************************************************************
CSEG_OPEN   SEGMENT   PARA   PUBLIC 'code'
  ASSUME  cs:cseg_open,ds:nothing,es:nothing,ss:nothing
;*****************************************************************************

PUBLIC	 Open_name_cache_seg									   ;AN000;
PUBLIC	 Open_name_Drive_Buff									   ;AN000;
PUBLIC	 End_Open										   ;AN000;
PUBLIC	 Chk_Flag										   ;AN000;

;---- FastOpen Functions Local Variables --------------

Current_Node	     DW    ?	     ;address of current node entry buffer		     ;AN000;
Current_Sibling      DW    ?	     ;address of current sibling node entry buffer		;AN000;
Current_Drive	     DW    ?	     ;address of current drive header			     ;AN000;
Matching_Node	     DW    -1	     ;flag						       ;AN000;
From_Delete	     DW    0	     ;= 1 if call is from DELETE function		    ;AN000;
Old_SI		     DW    0	     ;SI save area				     ;AN000;
Flag		     DB    0									;AN000;
Level		     DB    0	     ;depth level of the path					;AN000;
Dir_Info_Buffer      DD    ?	     ;Dir_Info buffer inside DOS				;AN000;
Extended_Info_Buffer DD    ?	     ;Extended Info buffer inside DOS			;AN000;
New_FEI_clusnum      DW    0									;AN000;
Packed_Name	     DB    11 dup (0)	   ;Space for packed dir name				;AN000;
Top		     DW    0									;AN000;
Temp		     DW    0									;AN000;
Bottom		     DW    0									;AN000;
Depth		     DB    0									;AN000;

Chk_Flag	     dw    0	     ; flag used by the analyser
func_cod	     db    0	     ; function code for analyser

;Following data area is filled during initialization
Open_name_cache_seg	   DW	 Cseg_Init     ; address of name cache buffer
Open_name_Drive_Buff	   DW	 0	       ; address of first drive buffer




;
;==============================================================================
;		    Pathname Tree Search
;
;  Element of each path name is represented by a node in the tree.  First
;  node is connected to the the Drive header through first child pointer
;  (DCH_Child_Ptr).  The first node may have one or more nodes underneath.
;  The first one is called the Child of this node and the others are the siblings
;  of the child node.  Previous node is connected to the first node through
;  the child pointer (nChild_Ptr) and the siblings are connected through the
;  sibling pointer (nSibling_Ptr).  Each node is connected to the previous
;  node through a backward pointer (nBackward_Ptr).  For example, to go to the
;  previous node from any of the siblings. It is necessary to go to the
;  child through previous siblings (if any) and then to the previous from the
;  child.  All this backward movement is using nBackward_Ptr.
;  Similarly to go to a child or sibling, nChild_ptr or nSibling_Ptr should be
;  used.  The strucure of drive header and the node are defined in Fastopen.inc
;

;==============================================================================
;Subroutine:  LOOKUP
;
;INPUT:
;    DS:SI -> path  (drive letter D: will be validated by Find_Drive_Cache_hdr)
;    ES:DI -> DIR_INFO buffer to be returned inside DOS
;    ES:CX -> FASTOPEN_Extended_Info buffer inside DOS
;    ES:BP -> Drive_Cache_Heade
;
;
;OUTPUT:
;     If the whole path is found,
;	 DS:SI--> 0
;	 ES:DI--> DIR_INFO buffer is filled with directory info
;	 ES:CX--> EXT_INFO buffer is filled with extended info
;
;     If partially found the path,
;	 DS:SI--> '\' after the matching directory name
;	 ES:DI--> DIR_INFO buffer is filled with directory info
;	 ES:CX--> EXT_INFO buffer is filled with extended info
;
;     If the Name_cache tree is empty, i.e.,no root directory name,
;	 DS:SI--> '\' after ':'
;	 ES:DI--> DIR_INFO buffer is undetermined
;	 ES:CX--> EXT_INFO buffer is undetermined
;
;==============================================================================

LOOKUP	PROC   FAR

	mov	cs:func_cod,al		   ; save function code
	cmp	From_Delete, 0		   ;call from DELETE function ??
	je	Look_Pack_Dir		   ;no, dont restore DS
	mov	DS,bx			   ;yes, restore DS
	ASSUME	DS:Cseg_Init
	jmp	short Look_save_regs	   ;save registers

Look_Pack_Dir:
	CALL	PACK_DIR_NAME		   ;on return drive letter => DL,

	CALL	FIND_DRIVE_CACHE_HEADER    ;find drive header address
					   ;on return ES:BP-->drive header
	jnc	look_save_regs		   ;drive buffer found
	jmp	lookup_error		   ;drive buffer not found

Look_Save_Regs:
	push	es
	push	di
	push	cx
	mov	ax, cs:Open_Name_Cache_Seg							   ;AN000;
	mov	es, ax			   ;ES = Name_Cache_Seg 				      ;AN000;
	ASSUME	es:Cseg_Init									   ;AN000;
	CALL	SET_LRU 		   ;set the Real LRU, if any.

	or	cs:Flag,Is_drive_head	   ;level of the tree. Drive header
	mov	cs:Matching_Node, -1	   ;Nothing found yet.
	mov	cs:Current_Drive, BP	   ;drive header
	mov	cs:Level, 0		   ;path level is 0

Lookup_Path:
	mov	cs:Current_Node, BP	   ;save current node address
	mov	cs:Current_Sibling,0fffeh  ;set no sibligs yet.
	mov	cs:Old_SI, si		   ;save current path address

	CALL	PACK_DIR_NAME		   ;get the next dir name from the path
	jc	Lookup_Done		   ;yes, found the whole path.

	test	cs:Flag, Is_drive_head	   ;dir name = drive header ?
	jz	Lp_Path1		   ;no-

	push	ds			   ;yes-drive header
	mov	ds,cs:Open_Name_Cache_Seg
	ASSUME	ds:Cseg_Init
	mov	BP, DS:[BP.DCH_Child_ptr]  ;BP-->first child node under drive hdr
	pop	ds
	ASSUME	ds:nothing
	jmp	short Lp_Path2

Lp_Path1:
	mov	BP, ES:[BP.nChild_ptr]	   ;BP--> child of current node

Lp_Path2:
	cmp	BP, -1			   ;no child?
	je	Lookup_Done		   ;Not found or partially found
	mov	cs:Current_Node, BP	   ;current_node = found node
	and	cs:Flag, Not_drive_head    ;reset the flag.

Lp_Cmpare:
	CALL	CMPARE			   ;look for path in current node
	je	Lookup_Found		   ;Yes, found a match. Next level for
					   ;possible remianing path

	mov	BP, ES:[BP.nSibling_ptr]   ;not found. Any siblings?
	mov	cs:Current_Sibling,BP
	cmp	BP, -1			   ;any more sibling?
	je	Lookup_Done		   ;no - done

	mov	cs:Current_Node, BP	   ;yes- make the found sibling as a current
	jmp	short Lp_Cmpare 	   ;node and search path in this node

Lookup_Found:
	inc	cs:Level
	mov	cs:Matching_Node,BP	   ;Used by Unfold_Name_Record

	CALL	PRE_LRU_STACK		   ;set the TEMP_LRU_Stack
	jmp	Lookup_Path		   ;continue to the next dir

Lookup_Done:
	mov	si, cs:Old_SI
	pop	cx			   ;restore Extended_Info buffer
	pop	di			   ;restore Dir_Info buffer
	pop	es			   ;the segment for the above buffers

	cmp	ax, -1
	je	Lookup_ERR		   ;error occured in Pack_Dir_Name.
	clc				   ;clear carry.
	jmp	short Lookup_Done1

Lookup_ERR:				   ;error exit
	stc

Lookup_Done1:
	test	cs:Flag, is_delete	   ;called by delete?
	jnz	Lookup_Return
	jc	Lookup_Exit		   ;If it was an error, don't change the carry flag

	CALL	UNFOLD_NAME_RECORD	   ;unfold the current node's record
Lookup_Exit:
	jmp	short Lookup_Return	   ;return to DOS.

Lookup_Error:				   ;error exit
	stc
	mov    ax,-1

Lookup_Return:				   ;return to Delete routine.
	CALL	Check_It		   ;check tree structure
	ret

LOOKUP	 ENDP





;==============================================================================
;SUBROUTINE: INSERT
;
;INPUT:    DS:DI -> Dir_Info in DOS
;	   ES:BX -> Fastopen_Extended_Info in DOS
;	   Current_Node, Current_Sibling, Current_Drive, Flag
;
;OUTPUT:   Information inserted into Name_cache_tree.
;
;   Any Sequential Insert operation should be preceded by a Look_up
;   operation. For ex., if the DOS wants to insert C:\DIR1\DIR2\File1
;   and suppose there is no matching name cache record for DIR1 in the tree.
;   Firstly DOS will try to look up C:\DIR1\DIR2\File1.  FASTOPEN will
;   return to DOS with DS:SI points to "\" after the drive letter.
;   Then, DOS will simply ask an insert operation with DS:DI, ES:BX
;   points to the information on "DIR1".  FASTOPEN will insert DIR1
;   onto the tree.  After that DOS will ask another insert
;   operation for DIR2.  FASTOPEN will insert DIR2.  Finally DOS will
;   ask to insert File1.
;
;   Suppose when DOS try to look up C:\DIR1\DIR2\File2 at this moment.
;   FASTOPEN will return to DOS with DS:SI points to "\" after DIR2 (since
;   DIR2 information is already in the name cache tree).  Then DOS will ask
;   to insert File2.
;
;   Any Insert operation of subdirectory name which is deeper than (Number_
;   of_Entries - 1) will not be inserted but will just return.
;   Also, for the safety reason, if the would be freed node (=LRU node) is
;   the same as the Current_Node, there will be no insertion. (This is a simple
;   safety valve.  A more smart logic can look for the next **legitimately
;   available** LRU node to use, or sometimes, simply replace the contents of the
;   entry if adequate. But this will increase the complexity greatly, and I
;   think the current logic is still practical enough to use despite of the
;   possible small window of performance degradation in a very special cases. J.K.)
;
;==============================================================================

INSERT	PROC   FAR
	mov	cs:func_cod,al			; save function code
	inc	cs:Level			;increment directory level
	xor	ax,ax
	mov	al, cs:Level
	inc	al
	mov	bp, cs:Current_Drive		;BP-->address of current drive header
	push	ds
	mov	ds,cs:Open_Name_Cache_Seg	;DS=name cache segment

	ASSUME	ds:Cseg_Init									   ;AN000;
	cmp	ax, ds:[bp.DCH_Num_Entries]	;Level > (Num_Entries - 1) ?
	pop	ds
	ASSUME	ds:nothing
	jbe	Insert_it			;no- insert it
	jmp	short Insert_return		;yes return

Insert_it:
	or	cs:Flag, is_insert

	CALL	GET_FREE_NODE		   ;AX = offset value of the available
					   ;name_record in Name_Cache_Seg.
	jc	I_Exit			   ;Current node = would-be freed node.

	CALL	MAKE_NAME_RECORD	   ;Fill the above name record entry.
					   ;ES was changed to Name_Cache_Seg.

	mov	bp, cs:Current_Node	   ;set BP to current_node
	mov	bx, bp			   ;save it into bx
	cmp	cs:Current_Sibling,0fffeh  ;current node sibling node ??
	je	I_Child 		   ;no-child of preceding node
	mov	es:[bp.nSibling_ptr], ax   ;yes-make new node sibling of
	jmp	short I_Done		   ;current node

I_Child:				   ;set nChild_ptr
	test	cs:Flag,Is_drive_head	   ;drive level?
	jnz	I_Child_first		   ;Yes, must be the first child
	mov	es:[bp.nChild_ptr], ax	   ;no-make ndew node child of
	jmp	short I_Done		   ;current node

I_Child_first:				   ;this is the first child in this drive.
	push	ds
	mov	ds,cs:Open_Name_Cache_Seg							   ;AN000;
	ASSUME	ds:Cseg_Init									   ;AN000;
	mov	ds:[bp.DCH_Child_ptr],ax   ;make new node 1st child current drive
	pop	ds
	ASSUME	ds:nothing
	mov	bx, cs:Current_Drive	   ;change bx to Current_Drive
	and	cs:Flag, Not_drive_head    ;reset the flag

I_Done:
	mov	bp, ax
	mov	es:[bp.nBackward_ptr],bx ;set the backward ptr of the inserted node.

	CALL	PRE_LRU_STACK		   ;save this inserted record temporarily.

	mov	cs:Current_Node,bp	   ;make new node current node
					   ;any subsequent insert operation
	mov	cs:Current_Sibling,0fffeh  ;should be installed as a child

I_Exit:
	and	cs:Flag, not_insert	   ;set not insert flag

Insert_return:
	CALL	Check_It		   ;check tree structure
	ret				   ;return

INSERT	ENDP






;==============================================================================
;Subroutine: DELETE
;
;INPUT:   DS:SI -> path
;	  ES:BP -> drive_cache_header (for Look_Up operation)
;
;OUTPUT:  if found, then remove the matching Name_Record will be removed from
;	  the tree and from the LRU chain.  The freed entry will be placed
;	  on top of the LRU chain.
;
;==============================================================================

DELETE	 PROC	FAR

	mov	cs:func_cod,al		   ; save function code
	CALL	PACK_DIR_NAME		   ;drive letter => DL, 				      ;AN000;

	CALL	FIND_DRIVE_CACHE_HEADER    ;find drive header address
					   ;on return ES:BP-->drive header
	jc	d_err_exit		   ;error exit

	or	cs:Flag, is_delete	   ;set the flag for Look_up.
	push	ds			   ;save DS in BX since it is going to be
	pop	bx			   ;changed for jumping to other segment
	push	ds
	mov	ax,cseg_Main
	mov	ds,ax			   ;DS=Main segment ID
	assume	ds:Cseg_Main
	mov	cs:From_Delete, 1	   ;set flag indicate that the call
					   ;is from DELETE function
	CALL	VECTOR_LOOKUP		   ;FAR call to Lookup function

	mov	cs:From_Delete, 0	   ;reset from delete flag
	pop	ds
	ASSUME	ds:nothing
	jc	D_err_Exit		   ;indirectly in the same segment

	cmp	byte ptr ds:[si], 0	   ;found the whole path?
	jne	D_err_Exit		   ;No.

;At this point, Current_Node = BP.
	mov	bx, cs:Open_Name_Cache_Seg
	mov	es, bx			   ;set ES to name_cache_seg.
	ASSUME	es:Cseg_Init

Delete_Node:
	cmp	es:[bp.nChild_ptr], -1	   ;No children?
	jne	D_err_Exit
	CALL	REMOVEFROMTREE		   ;remove the node while maintaing the
					   ;integrity of the tree.

	mov	es:[bp.nCmpct_Dir_Info], ' ' ;mark that this entry is free!!!

D_LRU_MRU:
	CALL	REMOVEFROMLRUCHAIN	   ;Remove BP from the LRU,MRU chain

	mov	si, cs:Current_Drive	   ;Now let the deleted node to be the
	push	ds			   ; LRU node
	mov	ds,cs:Open_Name_Cache_Seg
	ASSUME	ds:Cseg_Init									   ;AN000;

	mov	bx, ds:[si.DCH_LRU_ROOT]   ;es:bx -> first node
	mov	es:[bp.nLRU_ptr],bx	   ;Target.nLRU_ptr -> first node
	mov	es:[bx.nMRU_ptr],bp	   ;First_node.nMRU_ptr -> target
	mov	ds:[si.DCH_LRU_ROOT],bp    ;LRU_ROOT -> target
	mov	es:[bp.nMRU_ptr],-1
	pop	ds
	ASSUME	ds:nothing
	jmp	short	D_Exit		   ;exit

D_err_Exit:				   ;error exit
	stc
	mov	ax, -1

D_Exit:
	and	cs:Flag, not_delete	   ;reset the flag
	CALL	Check_It		   ;check tree structure
	ret				   ;return

DELETE	 ENDP





;==============================================================================
;Subroutine:  UPDATE
;
;INPUT:  If AH = 0, then update Dir_Entry area.
;	     ES:DI -> Dir_entry ("dir_first" is the key to search).
;	     DL = Logical Drive number (0 = A, 1 = B, ...).
;
;	 If AH = 1, then update "Fastopen_extended_info.FEI_clusnum".
;	     DL = Logical Drive number (0 = A, 1 = B, ...)
;	     CX = The value of "dir_first" to search.
;	     BP = new value of FEI_clusnum in the extended_info area.
;
;	If AH = 2, then delete the entry. Same effect as Delete function
;	     except this time the keys used to delete are;
;	     DL = logical drive number
;	     CX = the value of "dir_first" to search.
;
;	If AH = 3, then delete the entry. Same effect as Delete function
;	     except this time the keys used to delete are;
;	     DL = logical drive number
;	     DH = directory position
;	     DI = directory sector (low value)
;	     CX = directory sector (high value)
;
;
;OUT:  if found, then data is updated
;      else CY and AX = -1.
;
;    This routine use "starting cluster number" and "drive letter"
;    as a key to find the name record.	Usually the reason is DOS
;    does not have any "full path" information about the file when
;    it has to call this routine to update the information.
;    It follows the MRU chain until it finds the name record or
;    until it reaches the free name record (identified by the
;    Directory name starting with ' '), or until the end of
;    the MRU chain.
;
;==============================================================================

UPDATE	PROC	FAR

	mov	cs:func_cod,al		 ; save function code
	cmp	ah, 0			 ;update directory entry ?
	je	Update_Dir_Entry	 ;yes-
	cmp	ah, 1			 ;update extended info ?
	je	Update_Extended_clusnum  ;yes-
	cmp	ah, 2			 ;delete based on first clus num ?
	je	Update_Delete		 ;yes-
	cmp	ah, 3			 ;delete based directory sector ?
	je	Update_Delete1		 ;yes-

U_ERROR:				 ;no - error exit
	stc
	jmp	short  Update_Exit

Update_Delete:				; same as delete
	CALL	FIND_CLUSTER_NUMBER	; find name entry using first cluster
	jc	U_ERROR
	jmp	Delete_Node		; if found, delete entry

Update_Delete1: 			; same as delete (PTR P3718  3/10/88)
	CALL	FIND_DIR_SECTOR 	; find name entry using directory
	jc	U_ERROR 		; sector and directory position
	jmp	Delete_Node		; if found, delete node

Update_Dir_Entry:
	mov	cx, es:[di.dir_first]
	push	es			;save Dir_Info pointer ES:DI
	push	di
	CALL	FIND_CLUSTER_NUMBER
	pop	si			;restore Dir_Info pointer in DS:SI
	pop	ds
	jc	U_ERROR 		;error-if not found

	push	bp			;found the entry
	pop	di
	add	di, nCmpct_Dir_Info	;ES:DI->Name_Record.nCmpct_Dir_Info
	mov	cx, ODI_head_leng
	REP	MOVSB			;update Cmpct_dir_info head section
	add	si, ODI_skip_leng
	mov	cx, ODI_tail_leng
	REP	MOVSB			;update tail section
	jmp	short  Update_Exit	;exit

Update_Extended_clusnum:		;update extended info field
	mov	cs:New_FEI_clusnum,bp
	CALL	FIND_CLUSTER_NUMBER	;Find entry based first cluster number
	jc	U_ERROR

	add	bp, nExtended_Info	;es:bp -> Name_record.nExtended_Info
	mov	bx, cs:New_FEI_clusnum
	mov	es:[bp.FEI_clusnum],bx

Update_Exit:
	CALL	Check_It		   ;check tree structure
	ret				;return

UPDATE	 ENDP






;==============================================================================
;Subroutine:  FP_PURGE	  Rest Name Cache Buffers
;
;INPUT:  Main_Name_Drive_Buff  -  Offset to Name cache buffer
;	 Main_Name_Cache_Seg   -  Name cache seg id
;	 DL = Drive ID
;
;OUT:	 Buffer is purged
;
;==============================================================================

FP_PURGE   PROC    FAR

	mov	si,Open_Name_Drive_Buff        ; SI-->first Name drive cache buff
	mov	es,Open_Name_Cache_Seg	       ; ES = name cache seg ID
	mov	bx,es:[si].DCH_Name_Buff       ; BX-->Name cache buffer
	inc	dl			       ; DL=drive number
	add	dl,040H 		       ; convert drive num to drive letter

; Search for the name drive header corresponds to the drive letter
Purge_Drv_Loop:
	cmp	es:[si].DCH_Drive_Letter,dl    ; drive letter match ??
	je	Purge_drive_cache	       ; yes - set drive cache
	add	si, size Drive_Cache_Header    ; no - get address of next drive cache
	jmp	purge_drv_loop		       ; try next name drive header

Purge_Drive_Cache:			       ; SI-->drive header
	mov	bx,es:[si].DCH_Name_Buff       ; BX-->Name cache buffer
	mov	cx,es:[si].DCH_num_entries     ; get number of name records
	mov	ax,bx			       ; save last name record address
	mov	es:[bx].nMRU_ptr, -1	       ; make first MRU -1
	jmp	short set_start

Set_Up_Names:
	mov	es:[bx].nMRU_ptr,ax		;save last name record as MRU entry
	add	ax, size Name_Record		;AX = last name record = current name record

Set_Start:
	mov	es:[bx].nChild_ptr, -1		;no children or siblings
	mov	es:[bx].nsibling_ptr, -1	;right now
	mov	es:[bx].nBackward_ptr, -1

	push	di
	push	ax
	mov	ax, '  '                        ;AX = ' '
	mov	di, bx				;DI-->current name record
	add	di, nCmpct_Dir_Info		;blank out the Dir name area
	stosb					;in the name record
	stosw
	stosw
	stosw
	stosw
	stosw
	pop	ax				; AX = last name record address
	pop	di

	dec	cx				;update record count
	jcxz	purge_exit			;exit if last name record is done
	mov	dx,bx
	add	dx, size Name_Record		;DX-->next name record
	mov	es:[bx].nLRU_ptr,dx		   ;set LRU pointer - next name record
	add	bx, size Name_Record
	jmp	set_up_names			;set next name record

Purge_exit:
	clc
	ret

FP_PURGE    ENDP



;----------------------------------------------------------------------------
;		    FASTOPEN  SUPPORT ROUTINES
;----------------------------------------------------------------------------
;
; PROCEDURE:  Find_Drive_Cache_Header
;
; Function:  Validate drive ID and find address of drive cache header
;
;IN:   DL - drive letter
;      Drive_Header_Start ;label
;      Flag.
;
;OUT:  If CY = 0    Drive Header found
;	     ES:BP -> Drive_Cache_Header,
;
;      If CY = 1    Drive Header not found
;
;----------------------------------------------------------------------------

FIND_DRIVE_CACHE_HEADER   PROC	  NEAR

	mov	bp, cs:Open_name_drive_buff
	push	ds
	mov	ds,cs:Open_Name_Cache_Seg							   ;AN000;
	ASSUME	ds:Cseg_Init				;DS:BP-->first drive header    ;AN000;

FDCH_while:
	cmp	byte ptr ds:[bp.DCH_Drive_Letter], dl	; drive letter match
	jne	fdch_chk_end				; no - check next header
	clc						; yes - exit
	jmp	short FDCH_Exit

FDCH_Chk_End:
	cmp	byte ptr ds:[bp.DCH_Sibling_ptr], -1	; is this last header ?
	je	FDCH_Not_Found				; yes - header not found
	add	bp, size Drive_Cache_Header		; no - get next header
	jmp	short	FDCH_while			; look for match

FDCH_Not_Found:
	stc						;not found

FDCH_Exit:						;ES:BP-->header if found
	pop    ds
	ASSUME ds:nothing				;return
	ret

FIND_DRIVE_CACHE_HEADER     endp




;----------------------------------------------------------------------
; PROCEDURE:  GET_FREE_NODE
;
; called by Insert. The LRU node pointed DCH_LRU_ROOT is returned in AX
; and DCH_LRU_ROOT points to the following node in LRU chain.
; If the node is not an empty node, then it will be removed from the
; tree.
;
; IN:  Current_Drive, Current_Node
;
; OUT: AX = offset of the free node in Name_Cache_Seg
;     Other registers saved.
;----------------------------------------------------------------------

GET_FREE_NODE	PROC	NEAR

	push	es				 ;save registers
	push	di
	push	si
	push	bp

	mov	ax, cs:Open_Name_Cache_Seg							   ;AN000;
	mov	es, ax				;ES=Name cache segment				  ;AN000;
	ASSUME	es:Cseg_Init									   ;AN000;
	mov	si, cs:Current_Drive		;SI-->drive_cache_header
	push	ds
	mov	ds,cs:Open_Name_Cache_Seg
	ASSUME	ds:Cseg_Init
	mov	ax, ds:[si.DCH_LRU_ROOT]	;get the LRU node
	pop	ds
	ASSUME	ds:nothing

	cmp	ax, cs:current_Node		;LRU node=Current Node ??
	je	GFN_skip			;yes-

	mov	bp, ax				;BP=Current node
	mov	di, es:[bp.nLRU_ptr]		;DI= current LRU node's following node
	mov	es:[di.nMRU_ptr],-1		;set that node's MRU ptr
	push	ds
	mov	ds,cs:Open_Name_Cache_Seg	;DS=Name cache segment
	ASSUME	ds:Cseg_Init
	mov	ds:[si.DCH_LRU_ROOT],di 	;connect previous node to
	pop	ds				;next node
	ASSUME	ds:nothing

	cmp	byte ptr es:[bp.nCmpct_Dir_Info],' ';an empty node?
	je	GFN_OK			      ;then no problem.

	CALL	RemoveFromTree		    ;otherwise, it should be removed
					    ;from the tree.
GFN_OK:
	clc
	jmp	short	GFN_ret

GFN_Skip:
	stc

GFN_ret:
	pop	bp
	pop	si
	pop	di
	pop	es
	ret				    ;return

GET_FREE_NODE	endp




;
;----------------------------------------------------------------------
; PROCEDURE:   PRE_LRU_STACK
;
; When called by Look_up, Insert routine, the requested target node (BP)
; will be temporarily removed from LRU,MRU chain (until SET_LRU routine
; call), and will be pushed into a logical stack.  Actually, this routine
; will not use a stack, but try to get the effect of the use of stack
; to keep the history of target nodes in "REVERSE" LRU order as follows;
; {    inc Depth;
;      if Depth == 1 then Bottom = BP;
;			  Bottom.LRU_ptr = -1;
;			  Bottom.MRU_ptr = -1;
; else if Depth == 2 then Top = BP;
;			  Top.LRU_ptr = Bottom;
;			  Bottom.MRU_ptr = Top;
;			  Top.MRU_ptr = -1;
; else if Depth >= 3 then Temp = Top;
;			  Top = BP;
;			  Top.LRU_ptr = Temp;
;			  Temp.MRU_ptr = Top;
;			  Top.MRU_ptr = -1;
; }
;
;IN:  Depth, Top, Bottom, Temp,
;     Requested target node (BP)
;     ES = Name_Cache_Seg
;
;OUT: Target node removed from LRU,MRU chain.
;     Target node's history saved in reverse LRU order.
;     If called by "Delete" routine, then will just exit.
;     If called by "Insert" routine, then will not attempt
;     to remove the target node.
;----------------------------------------------------------------------

PRE_LRU_STACK	PROC	NEAR

	test	cs:Flag, is_delete	   ;invoked by Delete routine
	jnz	PLS_Exit
	test	cs:Flag, is_insert	   ;called by Insert routine
	jnz	PLS_Push

	CALL	RemoveFromLRUChain	;remove BP from the chain.

PLS_Push:
	push	di

	inc	cs:Depth
	cmp	cs:Depth, 1
	jne	PLS_Top
	mov	cs:Bottom, bp		   ;bottom = bp
	mov	es:[bp.nLRU_ptr], -1
	jmp	short PLS_Done

PLS_Top:
	cmp	cs:Depth, 2
	jne	PLS_Temp
	mov	cs:Top, bp		   ;Top = bp
	mov	di, cs:bottom		   ;di = bottom

PLS_com:
	mov	es:[bp.nLRU_ptr],di	;Top.LRU_ptr = bottom
	mov	es:[di.nMRU_ptr],bp	;Bottom.MRU_ptr = top
	jmp	short PLS_Done

PLS_Temp:
	mov	di, cs:Top		   ;di = Top
	mov	cs:Temp, di		   ;Temp = di
	mov	cs:Top, bp		   ;Top = bp
	jmp	short PLS_com

PLS_Done:
	mov	es:[bp.nMRU_ptr],-1
	pop	di

PLS_Exit:
	ret

PRE_LRU_STACK	endp
;





;----------------------------------------------------------------------
;PROCEDURE:  SET_LRU
;
;INPUT:  Depth, Top, Bottom, Current_Drive, ES = Name_Cache_Seg
;
;OUT: If Depth == 0 then exit
; Pre_LRU_Stack procedure already maintained a reverse order LRU
; mini chain.  Set_LRU will just put the top after the last node
; of the current LRU chain;
; { Get the last node of LRU chain.
;   if Depth == 0 then exit;
;   if Depth == 1 then Last_Node.LRU_ptr = Bottom;
;		       Bottom.MRU_ptr = Last_Node;
;		       MRU_ROOT = Bottom;
;   if Depth >= 2 then Last_Node.LRU_ptr = Top;
;		       Top.MRU_ptr = Last_Node;
;		       MRU_ROOT = Bottom;
;   Depth = 0;
; }
;----------------------------------------------------------------------

SET_LRU   PROC	  NEAR

	cmp	cs:Depth, 0		   ;nothing in the stack?
	je	SL_Exit

	push	si
	push	di
	push	bx
	mov	si, cs:Current_Drive	   ;cs:si -> Drive_Cache_Header
	push	ds
	mov	ds,cs:Open_Name_Cache_Seg							   ;AN000;
	ASSUME	ds:Cseg_Init									   ;AN000;
	mov	di, ds:[si.DCH_MRU_ROOT] ;es:di -> Last node in LRU chain

	cmp	cs:Depth, 1
	jne	SL_Other

	mov	bx, cs:Bottom
	mov	es:[di.nLRU_ptr],bx	;Last_Node.LRU_ptr = Bottom
	mov	es:[bx.nMRU_ptr],di	;Bottom.MRU_ptr = Last_Node
	mov	ds:[si.DCH_MRU_ROOT],bx ;MRU_ROOT = Bottom
	jmp	short SL_Done

SL_Other:				;Depth >= 2
	mov	bx, cs:Top
	mov	es:[di.nLRU_ptr],bx
	mov	es:[bx.nMRU_ptr],di
	mov	bx, cs:Bottom
	mov	ds:[si.DCH_MRU_ROOT],bx

SL_Done:
	pop	ds
	ASSUME	ds:nothing
	mov	cs:Depth, 0		   ;reset the Depth
	pop	bx
	pop	di
	pop	si

SL_Exit:
	ret

Set_LRU endp





;----------------------------------------------------------------------
; Procedure RemoveFromLRUChain
;
;IN:  Target node (BP) to be removed
;     Current_drive
;     ES - Name_Cache_Seg
;
;OUT:  Target node removed from the LRU,MRU chain. LRU,MRU chain
;     updated.
;
;----------------------------------------------------------------------

RemoveFromLRUChain     PROC    near

	push	bx
	push	di
	push	si

	mov	si, cs:Current_drive	   ;cs:si-> Drive_cache_header
	mov	bx, es:[bp.nMRU_ptr]	;es:bx-> Preceding node
	mov	di, es:[bp.nLRU_ptr]	;es:di-> Following node
	cmp	bx, -1			;Is target the first node?
	je	RFLC_first_node
	cmp	di, -1			;Is target the last node of LRU chain?
	je	RFLC_last_node
	mov	es:[bx.nLRU_ptr],di	;Preceding.LRU_ptr->following node
	mov	es:[di.nMRU_ptr],bx	;Following.MRU_ptr->preceding node
	jmp	short RFLC_done

RFLC_first_node:
	push	ds
	mov	ds,cs:Open_Name_Cache_Seg							   ;AN000;
	ASSUME	ds:Cseg_Init									   ;AN000;
	mov	ds:[si.DCH_LRU_ROOT],di ;LRU_ROOT-> following node
	pop	ds
	ASSUME	ds:nothing
	mov	es:[di.nMRU_ptr], -1	;Following node's MRU_ptr
	jmp	short RFLC_done

RFLC_last_node:
	push	ds
	mov	ds,cs:Open_Name_Cache_Seg
	ASSUME	ds:Cseg_Init
	mov	ds:[si.DCH_MRU_ROOT],bx ;MRU_ROOT-> preceding node
	mov	es:[bx.nLRU_ptr], -1	;Preceding node's LRU_ptr
	pop	ds
	ASSUME	ds:nothing

RFLC_done:
	pop	si
	pop	di
	pop	bx
	ret

RemoveFromLRUChain	endp
;



;----------------------------------------------------------------------
; Proceure  RemoveFromTree
;
;IN:  BP - offset of node to be removed from the tree
;	   This node shoud not be a subdirectory that is not empty!!!
;      ES - Name_Cache_Seg
;      Current_Drive
;
;OUT:  The node will be freed from the tree.
;     The neighbor's Child_ptr, Sibling_ptr, Backward_ptr are adjusted
;     accordingly.
;     The freed node's child_ptr, sibling_ptr, backward_ptr are reset to -1.
;----------------------------------------------------------------------

REMOVEFROMTREE	 PROC	 NEAR

	push	bx
	push	dx

	mov	bx, es:[bp.nBackward_ptr]	;get the preceding node
	mov	dx, es:[bp.nSibling_ptr]	;get the sibling node
	cmp	bx, cs:Current_Drive
	je	RFT_First_Child 	;bp is the first child
	cmp	es:[bx.nChild_ptr],bp
	je	RFT_Child		;bp is the child of the preceding node
	mov	es:[bx.nSibling_ptr],dx ;bp is the Sibling of the preceding node
					;Update the preceding node's Sibling ptr
	jmp	short RFT_Reset

RFT_First_Child:
	push	ds
	mov	ds,cs:Open_Name_Cache_Seg							   ;AN000;
	ASSUME	ds:Cseg_Init									   ;AN000;
	mov	ds:[bx.DCH_Child_ptr],dx
	pop	ds
	ASSUME	ds:nothing
	jmp	short RFT_Reset

RFT_Child:
	mov	es:[bx.nChild_ptr],dx

RFT_Reset:				;reset the deleted node's tree pointers
	mov	es:[bp.nChild_ptr],-1
	mov	es:[bp.nSibling_ptr],-1
	mov	es:[bp.nBackward_ptr],-1

	xchg	dx,bx			;now, dx=preceding node, bx=following node
	cmp	bx,-1			;end of sibling?
	je	RFT_ret
	mov	es:[bx.nBackward_ptr],dx;modify backward_ptr of the sibling node

RFT_ret:
	pop	dx
	pop	bx
	ret				;return

REMOVEFROMTREE	endp
;




;----------------------------------------------------------------------
; Procedure CMPARE
;
;IN: Packed name
;    BP = target node
;
;OUT: ZERO flag set when compare O.K.
;     DI destroyed.
;----------------------------------------------------------------------

CMPARE	PROC	near

	push	ds
	push	si
	mov	cx, 11
	push	cs
	pop	ds
	mov	si, offset cs:Packed_Name	   ;ds:si -> Packed_Name
	mov	di,bp
	add	di,nCmpct_Dir_Info		;es:di -> bp.nCmpact_Dir_Info
	REPE	CMPSB
	pop	si
	pop	ds
	ret
CMPARE	endp




;
;----------------------------------------------------------------------
; Procedure:  MAKE_NAME_RECORD
;
;IN:  DS:DI -> Dir_Info, ES:BX -> Extended_Info
;     AX = offset of the Name_Record entry in Name_Cache_Seg.
;
;OUT: Name_Record in Name_Cache_Seg filled.
;     nLRU_ptr, nChild_ptr, nSibling_ptr and nMRU_ptr are set to -1 for now.
;     ES, SI, DI destroyed.  ES will be Name_Cache_Seg.
;----------------------------------------------------------------------

MAKE_NAME_RECORD      PROC     NEAR

	push	ds			;save DS
	push	ax

	push	es			;save Extended_Info seg in DOS
	push	di
	pop	si			;DS:SI -> Dir_Info
	mov	di, cs:Open_Name_Cache_Seg							   ;AN000;
	mov	es, di										   ;AN000;
	ASSUME	es:Cseg_Init									   ;AN000;
	mov	di, ax			;ES:DI -> Name_Record
	mov	ax, -1
	mov	es:[di.nLRU_ptr],ax	;initialize pointers
	mov	es:[di.nChild_ptr],ax
	mov	es:[di.nSibling_ptr],ax
	mov	es:[di.nMRU_ptr],ax
	add	di, nCmpct_Dir_Info	;ES:DI -> Name_Record.nCmpct_Dir_Info
	mov	cx, ODI_head_leng	;currently 10.
	rep	movsb			;Move header part
	add	si, ODI_skip_leng	;DS:SI -> tail part of Dir_Info
	mov	cx, ODI_tail_leng
	REP	MOVSB			;move tail part.

	pop	ds			;restore Extended_Info seg in DS!!!
	mov	si, bx			;DS:SI -> Extended_Info
	mov	cx, size Fastopen_Extended_Info
	rep	movsb			;Move Extended_Info
	pop	ax
	pop	ds			;Restore DS

	ret				;return

MAKE_NAME_RECORD	ENDP
;




;----------------------------------------------------------------------
; Procedure Unfold_Name_Record
;
;IN:  Matching_Node, ES:DI -> Dir_Info buffer, ES:CX -> Extended_Info buffer
;
;OUT: if no matching node is found, then just return
;     else Dir_Info, Extended_Info buffer are filled.
;----------------------------------------------------------------------

Unfold_Name_Record     PROC	near

	cmp	cs:Matching_Node, -1
	je	UNR_Exit		;just exit
	push	ds
	push	si
	push	di
	push	cx			;save extended_info addr

	mov	si, cs:Open_Name_Cache_Seg							   ;AN000;
	mov	ds, si										   ;AN000;
	ASSUME	ds:Cseg_Init									   ;AN000;
	mov	si, cs:Matching_Node
	add	si, nCmpct_Dir_Info	;DS:SI -> Cmpct_Dir_Info

	mov	cx, ODI_head_leng	;Dir_Info header length
	REP	MOVSB			;Cmpct_Dir_Info.CDI_file_name -> ODI_head

	add	di, ODI_skip_leng	;length of Skiped part of Dir_Info
	mov	cx, ODI_tail_leng	;Dir_Info tail length
	REP	movsb			;Cmpct_Dir_Info.CDI_Time -> ODI_tail
					;At this moment, SI -> nExtended_Info

	pop	di			;ES:DI -> Extended_info
	push	di			;save di again for cx.
	mov	cx, size Fastopen_Extended_Info
	REP	movsb

	pop	cx			;restore extended_info addr
	pop	di
	pop	si
	pop	ds
	ASSUME	ds:nothing
UNR_Exit:
	ret				;return

Unfold_Name_Record	endp
;




;----------------------------------------------------------------------
; PROCEDURE:  PACK DIR_NAME
;
; Parse the name off of DS:SI into Packed_Name.  If called first time and
; DS:[SI+1] = ':' then it is ASSUMEd to be a drive letter and it will be
; returned in DL and SI will points to '\' after ':'.  If it was a directory
; name then Packed_Name will be set and SI points to '\' or 0 after the
; parsed directory name or filename.  This routine will check DS:[SI] when
; called to see if it points to '\' or 0.  If it points to '\' then
; it is ASSUMEd that the user want to skip the delimiter.  If it was 0,
; then this routine will set carry.  So, with a given drive,path string,
; the user is going to keep calling this routine until it returns
; with carry set that tells the end.
;----------------------------------------------------------------------

PACK_DIR_NAME	PROC	NEAR

	cmp	byte ptr ds:[si], 0	;end of path ??
	jne	PDN_Drive		;no-check for drive letter
	stc
	jmp	short PDN_Exit		;yes-exit

PDN_Drive:
	cmp	byte ptr ds:[si+1], ':' ;drive letter terminater?
	jnz	PDN_chk_skip		;no -
	mov	dl, byte ptr ds:[si]	;yes-set DL to the drive letter
	inc	si
	inc	si			;set SI -> '\' after ':'
	jmp	short PDN_Exit		;then exit

PDN_chk_skip:
	cmp	byte ptr ds:[si], '\'   ;delimeter?
	jne	PDN_Path		;no-
	inc	si			;yes-skip delimiter
	cmp	byte ptr ds:[si], 0	;end of path ??
	jne	PDN_Path		;no-pack path name
	stc				;yes-In fact, the input from DOS was
	mov	ax, -1			;D:\,0.  FASTOPEN will treate
	jmp	short PDN_Exit		;this as an error.

PDN_Path:				;pack path name
	push	es
	push	di
	push	ax

	push	cs
	pop	es
	mov	di, offset cs:Packed_Name   ;ES:DI-->pack buffer

	mov	ax,'  '
	STOSB				;blank out the Packed_Name
	STOSW
	STOSW
	STOSW
	STOSW
	STOSW
	mov	di, offset cs:Packed_Name

PDN_GetName:
	LODSB				;DS:SI => AL, SI++
	cmp	al,'.'
	jz	PDN_SetExt
	or	al,al
	jz	PDN_GetDone
	cmp	al,'\'
	jz	PDN_GetDone
	STOSB
	jmp	short PDN_GetName

PDN_SetExt:
	mov	di, offset cs:Packed_Name+8

PDN_GetExt:
	LODSB
	or	al,al
	jz	PDN_GetDone
	cmp	al,'\'
	jz	PDN_GetDone

PDN_StoExt:
	STOSB
	jmp	PDN_GetExt

PDN_GetDone:
	dec	si			;set SI back to the delimeter or 0.
	pop	ax
	pop	di
	pop	es

PDN_Exit:
	ret

PACK_DIR_NAME	endp





;----------------------------------------------------------------------
; PROCEDURE:  FIND_CLUSTER_NUMBER
;
;IN:  DL = driver # (0 = A, 1 = B,...)
;     CX = The value of Dir_First in Name_Record to search.
;     Search Name_Record entries to find the matching starting cluster number.
;     The search uses MRU chain for efficiency.
;
;OUT: ES = Name_Cache_Seg
;     BP = Name_Record
;     if not found, carry bit.
;     ES, BP register changed.
;----------------------------------------------------------------------

FIND_CLUSTER_NUMBER    PROC    NEAR

	push	ax
	push	cx
	push	dx
	add	dl, 'A'                 ;convert to a drive letter

	CALL	FIND_DRIVE_CACHE_HEADER ;ES:BP -> driver header if found
	jc	FCN_exit		;exit if not found

	mov	dx, cx			;save the key in DX					   ;AN000;
	mov	ax, cs:Open_Name_Cache_Seg							   ;AN000;
	mov	es, ax										   ;AN000;
	ASSUME	es:Cseg_Init

	CALL	SET_LRU 		;clean up the LRU stack

	mov	cs:Current_Drive,bp   ;set Current_Drive (You should not set
					;Current_Drive before SET_LRU at any time!!!
	push	ds
	mov	ds,cs:Open_Name_Cache_Seg
	ASSUME	ds:Cseg_Init
	mov	cx, ds:[bp.DCH_Num_Entries]	;Max number to try
	mov	bp, ds:[bp.DCH_MRU_ROOT]	;get the start of MRU chaing
	pop	ds
	ASSUME	ds:nothing

FCN_while:
	cmp	es:[bp.nCmpct_Dir_Info], ' ' ;Is it a free node ?
	je	FCN_not_found		;then no reason to continue search.

	cmp	dx, es:[bp.nCmpct_Dir_Info.CDI_cluster] ;matching starting cluster # ?
	je	FCN_exit		;found it!!!

	mov	bp, es:[bp.nMRU_ptr]	;next MRU entry address
	cmp	bp, -1			;It was the end of MRU chain?
	je	FCN_not_found		;not found. End of search
	LOOP	FCN_while		;else compare cluster and contine...

FCN_Not_found:
	stc

FCN_exit:
	pop	dx
	pop	cx
	pop	ax
	ret

FIND_CLUSTER_NUMBER	ENDP




;----------------------------------------------------------------------
; PROCEDURE:  FIND_DIR_SECTOR	 (PTR 3718  3/10/88)
;
;     Search Name_Record using directory sector and directory position
;     for the name entry.
;
;IN:  DL = driver # (0 = A, 1 = B,...)
;     DI = Dirctory sector Low	value
;     CX = Dirctory sector high value
;     DH = Dirctory position
;
;OUT: ES = Name_Cache_Seg
;     BP = Name_Record
;     if not found, carry bit.
;     ES, BP register changed.
;----------------------------------------------------------------------

FIND_DIR_SECTOR   PROC	  NEAR

	push	ax
	push	cx
	push	dx
	add	dl, 'A'                  ;convert to a drive letter

	CALL	FIND_DRIVE_CACHE_HEADER  ;ES:BP -> driver header if found
	jc	FDIR_exit		 ; error if not found

	mov	ax, cs:Open_Name_Cache_Seg							   ;AN000;
	mov	es, ax										   ;AN000;
	ASSUME	es:Cseg_Init

	CALL	SET_LRU 		;clean up the LRU stack

	mov	ax,cx			; save directory sector high value
	mov	cs:Current_Drive,bp	;set Current_Drive (You should not set
					;Current_Drive before SET_LRU at any time!!!
	push	ds
	mov	ds,cs:Open_Name_Cache_Seg
	ASSUME	ds:Cseg_Init
	mov	cx, ds:[bp.DCH_Num_Entries]	;Max number to try
	mov	bp, ds:[bp.DCH_MRU_ROOT]	;get the start of MRU chaing
	pop	ds
	ASSUME	ds:nothing

FDIR_while:
	cmp	es:[bp.nCmpct_Dir_Info], ' ' ;Is it a free node ?
	je	FDIR_NOT_FOUND		;then no reason to continue search.

	cmp	di, word ptr es:[bp.nExtended_Info.FEI_dirsec] ;matching directory sector hi?
	jne	FDIR_Next		;check next entry

	cmp	ax, word ptr es:[bp.nExtended_Info.FEI_dirsec+2] ;matching directory sector low ?
	jne	FDIR_Next		;check next entry

	cmp	dh, es:[bp.nExtended_Info.FEI_dirpos] ;matching directory postion ?
	je	FDIR_Exit		;check next entry

FDIR_Next:
	mov	bp, es:[bp.nMRU_ptr]	;next MRU entry address
	cmp	bp, -1			;It was the end of MRU chain?
	je	FDIR_not_found		;not found. End of search
	loop	FDIR_while		;else compare cluster and contine...

FDIR_Not_found: 			; no found
	stc

FDIR_exit:
	pop	dx
	pop	cx
	pop	ax
	ret

FIND_DIR_SECTOR     ENDP





;--------------------------------------------------------------------------
; Procedure: CHECK_IT	   Call Fastopen  Tree Analyser to check the
;			   consistency of the Directory/File Tree strucutre.
;--------------------------------------------------------------------------
CHECK_IT   PROC    NEAR

       pushf				      ; save all registers
       push   ax
       push   bx
       push   cx
       push   dx
       push   si
       push   di
       push   ds
       push   es
       cmp    cs:Chk_flag,0		      ;Fastopen analyser enabled ??
       je     Check_Exit		      ;no - exit

       mov    ax,cs:Open_Name_Cache_Seg       ;yes-set multiplex function call
       mov    es,ax
       mov    ah,091h			      ;load Multiplex ID
       xor    al,al
       xor    cx,cx
       mov    cl,cs:func_cod		      ;CL=Fastopen Function code
       mov    di,cs:Current_Drive	      ;ES:DI-->current drive header
       INT    2FH			      ;call the analyser

Check_Exit:
       pop    es			      ;restore all registers
       pop    ds
       pop    di
       pop    si
       pop    dx
       pop    cx
       pop    bx
       pop    ax
       popf				      ;return
       ret

CHECK_IT    ENDP





; Calculate the size of the CSEG_OPEN Module in bytes
	IF  ($-Cseg_Open) MOD 16								   ;AN000;
	   ORG ($-Cseg_Open)+16-(($-Cseg_Open) MOD 16)						   ;AN000;
	ENDIF											   ;AN000;

END_OPEN   label   word




CSEG_OPEN    ends
     end