; ; File: BTreeMaint2.a ; ; Revision by: Kenny SC. Tung ; ; Copyright: © 1984-1990, 1992 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; 4/1/92 kc Changed the name prefex used to distinguish ; routines used by the external B-Tree manager ; from the versions used by the File System. ; ¥ Pre-SuperMario comments follow ¥ ; <6> 8/3/90 KST Total number of nodes is calculated based on LEOF, not PEOF (in ; ExtChkNode). ; <5> 7/6/90 KST Fixing a bug in "ExtUpdIKey" which should not do EXT.W ; <4> 4/11/90 KST Code cleanup. ; <3> 4/11/90 KST Use ExtbtMaxDepth and related equates. ; <2> 3/13/90 KST Adding for the first time. ; <1.1> 8/7/89 KST Code cleanup. ; <1.0> 6/14/89 KST New file added for the new implementation of BTreeMgr. ; <1.3> 5/4/89 KST Fixed a bug in ExtGetMaxkey. ; 5/4/89 KST Fixed a bug in ExtGetMaxkey, should add 2, not 1 ; <1.2> 3/2/89 DNF removed references to forROM; HFS now builds identically for ram ; or rom ; <1.1> 11/10/88 CCH Fixed Header. ; <1.0> 11/9/88 CCH Adding to EASE. ; <¥1.1> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles ; <1.0> 2/11/88 BBM Adding file for the first time into EASEÉ ; 10/25/85 BB Added vectors for ROM versions. ; 10/22/85 BB Moved ExtLocBTCB from BTIntf to ExtBTMaint2. ; 10/10/85 BB Added use of new MOVEQ equates for GetBlock and RelBlock. Added ; ExtGetMaxkey subroutine and a call to it in ExtBuildIRec. Did some ; minor code clean up. ; 9/26/85 BB Modified ExtGetNode to release the cache block after detecting a ; bad BTree node. ; 9/24/85 PWD Changed '.Word $F042' to _TFSDSErr macro. ; 9/23/85 BB Added ExtClrNode and a call to it in ExtInitNode. ; 9/23/85 BB Modified ExtRelNode to handle a null node pointer and to call ; ExtChkNode. ; 9/6/85 BB Fixed minor bugs in ExtGetNodeSiz and GetOffA. ; 8/29/85 BB Changed ExtChkNode to use a more efficient method for checking ; record offsets. ; 8/22/85 BB Added ExtGetNode,ExtRelNode, and ExtChkNode. ; 8/8/85 BB Modified ExtGetOffset and ExtInitNode for new node format. ; 7/31/85 BB Fixed bug in ExtLocRec which was causing the "write" problem. ; 7/17/85 BB Added ExtGetNodeSiz. Modified ExtGetRecA to also return record size. ; 7/8/85 BB Modified ExtGetLtSib/ExtGetRtSib to use links to locate sibling nodes ; instead of using the TPT. ; 6/10/85 BB Cleaned up some. ; 3/15/85 BB Modified to use A6 stack. ; 3/11/85 BB Added extend BTree file stuff. ; 2/25/85 BB Modified ExtInsertRec to return node number and record index of new ; record. ; 2/18/85 BB Modified ExtLocRec to support variable length keys in leaf nodes. ; 2/13/85 BB Removed default KeyCompare routine ; 1/17/85 BB Removed use of BTree Global area (BTG). ; 1/5/85 BB Modified ExtSearchNode to use external key compare routine. ; 1/5/85 BB Added KeyCompare routine. ; 1/5/85 BB Changed CopyRec to ExtLocRec to support return of key and data ; record pointers instead of copying that data. ; 10/1/84 BB Split off from BTmaint. ; ; To Do: ; ;__________________________________________________________________________________ ; ; FILE: ExtBTMaint2.text ; ; Function: These routines provide single-node BTree maintenance functions. ; ; External ; Routines: ExtBuildIRec - Builds an index record for a specified target node. ; ExtChkNode - Checks the validity of a node. ; ExtClrNode - Clears a node (to zero). ; ExtDeleteRec - Deletes a record from a BTree node. ; ExtGetMaxkey - Gets max key size rounded to word boundry. ; ExtGetNode - Gets a BTree node from disk. ; ExtGetNodeSiz - Gets the size of the data currently contained in a ; node (record data + offset overhead). ; ExtGetLtSib - Gets left sibling node for a given BTree node. ; ExtGetRtSib - Gets right sibling node for a given BTree node. ; ExtGetOffset - Gets the record offset and the pointer to the offset ; word for a given record index. ; ExtGetRecA - Gets the address of the record for a given record ; index. ; ExtInitNode - Gets a cache buffer for a new node and initializes it to ; an empty state. ; ExtInsertRec - Inserts a record into a BTree node. ; ExtLocBTCB - Locates the BTCB for a BTree file. ; ExtLocRec - Locates the key and data records for a specified ; BTree record. ; ExtLocTPR - Locates the Tree Path Record (TPR) for a given tree ; level. ; ExtMovOffLt - Move offsets left within a single node. ; ExtMovOffRt - Move offsets right within a single node. ; ExtMovRecLt - Move records left within a single node. ; ExtMovRecRt - Move records right within a single node. ; ExtRelNode - Releases the use of a node. ; ExtSearchNode - Searches a BTree node for a specified key. ; ExtUpdDRec - Updates the data portion of a BTree record. ; ExtUpdIKey - Updates the key portion of an index record. ; ; Internal ; Subroutines: None. ; BLANKS ON STRING ASIS PRINT OFF LOAD 'StandardEqu.d' INCLUDE 'BtreeEqu.a' INCLUDE 'BtreePrivate.a' ; Use ExtbtMaxDepth <11Apr90> PRINT ON PRINT NOGEN ExtBTMaint2 PROC EXPORT EXPORT ExtBuildIRec,ExtChkNode,ExtClrNode,ExtDeleteRec EXPORT ExtGetMaxkey,ExtGetNode,ExtGetNodeSiz,ExtGetLtSib,ExtGetRtSib,ExtGetOffset,ExtGetRecA EXPORT ExtInitNode,ExtInsertRec,ExtLocBTCB,ExtLocRec,ExtLocTPR EXPORT ExtMovOffLt,ExtMovOffRt,ExtMovRecLt,ExtMovRecRt EXPORT ExtRelNode,ExtSearchNode,ExtUpdDRec,ExtUpdIKey IMPORT ExtGetBlock,ExtRelBlock ; ;__________________________________________________________________________________ ; ; Routine: ExtBuildIRec ; ; Function: Builds an index record for a specified target node. The ; record is built in the BTree buffer. ; ; Input: A1.L - ptr(target node buffer) ; D0.W - target node number ; A4.L - pointer to BTCB ; ; Output: A1.L - ptr(new index record) in BTree buffer ; ; Called by: BTInsert ;__________________________________________________________________________________ ExtBuildIRec MOVE.L D2,-(SP) ; save regs MOVE.L D0,D2 ; save node number CLR.W D0 ; locate 1st record BSR ExtGetRecA ; ...in node MOVEA.L BTCVarPtr(A4),A1 ; locate record buffer LEA ExtbtVRecord(A1),A1 ; <11Apr90> JSR ExtUpdIKey ; move in the key BSR ExtGetMaxkey ; node # offset = max key size <10Oct85> MOVE.L D2,0(A1,D0.W) ; move in the node number <10Oct85> MOVE.L (SP)+,D2 ; restore regs RTS ; exit ExtBuildIRec ;__________________________________________________________________________________ ; ; Routine: ExtChkNode ; ; Function: Checks the validity of a node. ; ; Input: A1.L - pointer to node buffer ; A4.L - pointer to BTCB ; ; Output D0.W - result code ; 0 - ok ; BTBadNode - bad node structure detected ; ; Called by: ExtGetNode ; <26Jul90> KSCT use LEOF to calculate total nodes. ;__________________________________________________________________________________ ExtChkNode MOVEM.L D1-D2/A0-A2,-(SP) ; save registers MOVE.W BTCRefNum(A4),D1 ; locate the FCB MOVEA.L FCBSPtr,A2 ; ; ; check out the links ; MOVE.L FCBEof(A2,D1.W),D0 ; LEOF / node size <26Jul90> DIVU BTCNodeSize(A4),D0 ; = end node # + 1 MOVEQ #0,D1 ; MOVE.W D0,D1 ; D1 = end node # + 1 CMP.L NDFlink(A1),D1 ; forward link within range? BLS.S CNBadNode ; no, error -> CMP.L NDBlink(A1),D1 ; backward link within range? BLS.S CNBadNode ; no, error -> ; ; check node type ; note: valid node types are $FF (leaf node) to $02 (map node) ; MOVE.B NDType(A1),D0 ; node type + 1 ADDQ.B #1,D0 ; CMP.B #NDMapNode+1,D0 ; (node type +1) > (max type +1) ? BHI.S CNBadNode ; yes, error -> ; ; check node height ; MOVE.B NDNHeight(A1),D0 ; node height > tree depth? CMP.B BTCDepth+1(A4),D0 ; BHI.S CNBadNode ; yes, error -> ; ; check number of records ; CNChkNRecs MOVEQ #0,D1 ; D1 = node size MOVE.W BTCNodeSize(A4),D1 ; MOVEQ #-lenND,D0 ; max number of records ADD.L D1,D0 ; = (node size - length of ND) DIVU #6,D0 ; / (min record size + offset word) CMP.W NDNRecs(A1),D0 ; record count within range? BLO.S CNBadNode ; no, error -> ; ; check record offsets ; CNChkOff MOVE.W NDNRecs(A1),D1 ; loop index = # records MOVE.W D1,D0 ; locate free space offset <29Aug85> BSR ExtGetOffset ; MOVEQ #2,D2 ; prime previous offset to <29Aug85> ADD.L A0,D2 ; ptr(free space offset) + 2 <29Aug85> SUB.L A1,D2 ; - ptr(node) <29Aug85> @1 MOVE.W (A0)+,D0 ; get next offset <29Aug85> BTST #0,D0 ; odd offset? BNE.S CNBadNode ; yes, error -> CMPI.W #LenND,D0 ; offset >= min ? BLO.S CNBadNode ; no, error -> CMP.W D2,D0 ; offset < previous ? BHS.S CNBadNode ; no, error -> MOVE.W D0,D2 ; previous offset = current offset DBRA D1,@1 ; check next one -> BRA.S CNExit ; all done -> ; ; clean up and exit ; CNBadNode MOVEQ #BTBadNode,D0 ; result = 'bad node' <14Oct85> BRA.S CNExit1 ; exit -> CNExit CLR.W D0 ; result = 'ok' CNExit1 MOVEM.L (SP)+,D1-D2/A0-A2 ; restore registers TST.W D0 ; set up condition codes RTS ; exit ExtChkNode ;__________________________________________________________________________________ ; ; Routine: ExtClrNode ; ; Function: Clears a node to all zeroes. ; ; Input: A0.L - pointer to node buffer ; A4.L - pointer to BTCB ; ; Output none ; ; Called by: BTDelete ;__________________________________________________________________________________ ExtClrNode MOVEM.L D0-D1/A0,-(SP) ; save registers <23Sep85> MOVEQ #3,D1 ; loop index <10Oct85> ADD.W BTCNodeSize(A4),D1 ; = node size <10Oct85> LSR.W #2,D1 ; (in long words) <23Sep85> SUBQ.W #1,D1 ; - 1 <23Sep85> MOVEQ #0,D0 ; clear the node buffer <23Sep85> @1 MOVE.L D0,(A0)+ ; <23Sep85> DBRA D1,@1 ; <23Sep85> MOVEM.L (SP)+,D0-D1/A0 ; restore registers <23Sep85> RTS ; exit ExtClrNode <23Sep85> ;__________________________________________________________________________________ ; ; Routine: ExtDeleteRec ; ; Function: Deletes a record from a BTree node. ; ; Input: A1.L - ptr(node buffer) ; D1.W - index of record to be deleted ; A4.L - pointer to BTCB ; ; Output: none ; ; Called by: BTDelete,RotRecLt ;__________________________________________________________________________________ ExtDeleteRec MOVEM.L D2-D6/A2-A5,-(SP) ; save regs ; ; set up some common stuff ; MOVE.W D1,D5 ; save delete index MOVE.W D1,D0 ; get delete offset JSR ExtGetOffset ; MOVE.L A0,D6 ; ...D6 = ptr(delete offset) MOVE.W D0,D4 ; ...D4 = delete offset LEA -2(A0),A3 ; A3 = ptr(next offset) MOVE.W (A3),D3 ; D3 = next offset MOVE.W NDNRecs(A1),D0 ; get last offset JSR ExtGetOffset ; MOVE.L A0,A2 ; ...A2 = ptr(last offset) MOVE.W D0,D2 ; ...D2 = last offset ; ; Compress remaining records ; MOVE.L A1,A5 ; save ptr(node buffer) LEA 0(A5,D3.W),A0 ; source = ptr(next record) LEA 0(A5,D4.W),A1 ; dest = ptr(delete record) MOVE.W D2,D0 ; count = last offset SUB.W D3,D0 ; - next offset JSR ExtMovRecLt ; move the records SUB.W #1,NDNRecs(A5) ; decrement number of keys ; ; Adjust the offsets ; MOVE.L A3,A0 ; source = ptr(next offset) MOVE.L D6,A1 ; dest = ptr(delete offset) MOVE.W NDNRecs(A5),D0 ; count = last index SUB.W D5,D0 ; - delete index MOVE.W D4,D1 ; delta = delete offset SUB.W D3,D1 ; - next offset JSR ExtMovOffRt ; adjust the offsets DRExit MOVEM.L (SP)+,D2-D6/A2-A5 ; restore regs RTS ; return ;__________________________________________________________________________________ ; ; Routines: ExtGetLtSib (Get Left Sibling) ; ExtGetRtSib (Get Right Sibling) ; ; Function: Gets the left or right sibling node for a given BTree node. The ; sibling nodes are located using the forward/backward node links. ; ; Input: A0.L - pointer to node buffer containing subject node ; A4.L - pointer to BTCB ; ; Output: A1.L - pointer to node buffer containing sibling node ; D1.L - node number of sibling node ; 0 - no sibling ; D0.W - result code ; 0 - ok ; -n - IO error ;__________________________________________________________________________________ ExtGetLtSib MOVE.L (SP)+,-(A6) ; save return address on A6 stack MOVEM.L D2-D3,-(A6) ; save registers CLR.B D3 ; indicate ExtGetLtSib BRA.S GSRtSib1 ; use common code ExtGetRtSib MOVE.L (SP)+,-(A6) ; save return address on A6 stack MOVEM.L D2-D3,-(A6) ; save registers MOVEQ #1,D3 ; indicate ExtGetRtSib GSRtSib1 TST.B D3 ; getting left sibling ? BNE.S @2 ; no -> MOVE.L NDBlink(A0),D2 ; left sibling node number BRA.S @3 ; -> @2 MOVE.L NDFlink(A0),D2 ; right sibling node number @3 BNE.S @5 ; we have the sibling -> @4 CLR.L D1 ; indicate no sibling BRA.S GSExit ; exit @5 MOVEQ #0,D1 ; no GetBlock options <10Oct85> BSR.S ExtGetNode ; get node from disk BNE.S GSExit1 ; error -> MOVE.L D2,D1 ; return the node number MOVE.L A0,A1 ; ...and buffer address GSExit CLR.W D0 ; indicate no error GSExit1 MOVEM.L (A6)+,D2-D3 ; restore registers MOVE.L (A6)+,-(SP) ; put return address back on stack TST.W D0 ; set up condition codes RTS ; exit ExtGetLtSib/ExtGetRtSib ;__________________________________________________________________________________ ; ; Routine: ExtGetMaxkey ; ; Function: Gets maximum key size rounded to word boundry. ; ; Input: A4.L - pointer to BTCB ; ; Output D0.W - maximum key length ; ; Called by: BTInsert,BTDelete,BTGetRecord,BTSearch ;__________________________________________________________________________________ ExtGetMaxkey MOVEQ #2,D0 ; key length = 1 <10Oct85> ; 2, include length byte ADD.W BTCKeyLen(A4),D0 ; + max key length <10Oct85> LSR.W #1,D0 ; rounded down <10Oct85> LSL.W #1,D0 ; <10Oct85> RTS ; exit ExtGetMaxkey <10Oct85> ;__________________________________________________________________________________ ; ; Routine: ExtGetNode ; ; Function: Gets an existing BTree node from disk and verifies it. ; Note: this is a temporary interface, it will change for the new ; cache. ; ; Input: D1.B - GetBlock option flags ; D2.L - node number of desired node ; A4.L - pointer to BTCB ; ; Output D0.W - result code ; 0 = ok ; -n = error ; A0.L - pointer to buffer containing node ; ; Called by: BTInsert,BTDelete,BTGetRecord,BTSearch ;__________________________________________________________________________________ ExtGetNode MOVE.L (SP)+,-(A6) ; save return address on A6 stack MOVEM.L D1/A1,-(A6) ; save registers MOVE.W BTCRefNum(A4),D0 ; file refnum MOVEA.L BTCCQptr(A4),A1 ; ptr to cache queue JSR ExtGetBlock ; get the block BNE.S GNExit ; didn't get it -> MOVEA.L A0,A1 ; verify the node BSR ExtChkNode ; BEQ.S GNExit ; its ok -> <26Sep85> MOVE.W D0,-(A6) ; save result code <26Sep85> MOVEQ #kRBTrash,D1 ; set trash option <10Oct85> MOVEA.L BTCCQptr(A4),A1 ; ptr to cache queue <26Sep85> JSR ExtRelBlock ; release it <26Sep85> MOVE.W (A6)+,D0 ; restore result code <26Sep85> GNExit MOVEM.L (A6)+,D1/A1 ; restore registers MOVE.L (A6)+,-(SP) ; put return address back on stack TST.W D0 ; set up condition codes RTS ; exit ExtGetNode ;__________________________________________________________________________________ ; ; Routine: ExtGetNodeSiz (Get Node Size) ; ; Function: Gets the size of the data currently contained in a node ; (record data + offset overhead). ; ; Input: A1.L - pointer to node buffer ; A4.L - pointer to BTCB ; ; Output: D0.W - size of node data ;__________________________________________________________________________________ ExtGetNodeSiz MOVE.L D1,-(SP) ; save registers MOVE.W NDNRecs(A1),D1 ; number of records in node MOVE.W D1,D0 ; record data size JSR ExtGetOffset ; = free space offset SUBI.W #lenND,D0 ; - length of ND <06Sep85> LSL.W #1,D1 ; NRecs X 2 = overhead for offsets ADD.W D1,D0 ; rec data size + offsets = node data size MOVE.L (SP)+,D1 ; restore registers RTS ; exit ExtGetNodeSiz ;__________________________________________________________________________________ ; ; Routine: ExtGetOffset (Get Offset) ; ; Function: Gets the record offset and the pointer to the offset word ; for a given record index. ; ; Input: A1.L - pointer to node buffer ; D0.W - record index ; A4.L - pointer to BTCB ; ; Output: D0.W - record offset ; A0.L - address of offset word ;__________________________________________________________________________________ ExtGetOffset BSR.S GetOffA ; get ptr(offset) first MOVE.W (A0),D0 ; get the offset RTS ; return ; ; GetOffA (Get Offset Address) subroutine ; GetOffA SUBA.L A0,A0 ; position to offset base + 2 <06Sep85> MOVE.W BTCNodeSize(A4),A0 ; <06Sep85> ADDA.L A1,A0 ; <06Sep85> LSL.W #1,D0 ; index * 2 (bytes) NEG.W D0 ; negative byte index LEA -2(A0,D0.W),A0 ; ptr(offset) = (base - 2) + byte index RTS ; return ;__________________________________________________________________________________ ; ; Routine: ExtGetRecA (Get Record Address) ; ; Function: Gets the address and size of a BTree record given the record index. ; ; Input: A1.L - ptr(node buffer) ; D0.W - record index ; A4.L - pointer to BTCB ; ; Output: A0.L - record address ; D0.W - size of record ;__________________________________________________________________________________ ExtGetRecA MOVEM.L D1-D2,-(SP) ; save registers MOVE.W D0,D1 ; D1 = record index BSR.S ExtGetOffset ; get offset of target record MOVE.W D0,D2 ; D2 = target offset MOVE.W D1,D0 ; get offset to next record ADDQ.W #1,D0 ; BSR.S ExtGetOffset ; SUB.W D2,D0 ; size = next offset - target offset LEA 0(A1,D2.W),A0 ; ptr(record) = base + offset MOVEM.L (SP)+,D1-D2 ; restore registers RTS ; return ;__________________________________________________________________________________ ; ; Routine: ExtInitNode ; ; Function: Gets a cache buffer for a new node and initializes it to ; an empty state. ; ; Input: D1.L - node number of new node ; A4.L - pointer to BTCB ; ; Output D0.W - result code ; A0.L - ptr(cache buffer containing node) ; ; Called by: BTInsert ;__________________________________________________________________________________ ExtInitNode MOVE.L (SP)+,-(A6) ; save return address on A6 stack MOVEM.L D1-D2/A1,-(A6) ; save registers ; ; get cache buffer for new node ; @1 MOVE.L D1,D2 ; node number MOVE.W BTCRefNum(A4),D0 ; file refnum MOVEQ #kGBnoread,D1 ; no-read option <10Oct85> MOVEA.L BTCCQptr(A4),A1 ; cache queue ptr JSR ExtGetBlock ; get cache buffer BNE.S INExit1 ; error -> ; ; initialize the node ; BSR ExtClrNode ; clear the node first <23Sep85> MOVE.W BTCNodeSize(A4),D2 ; D2 = node size MOVE.W #lenND,-2(A0,D2.W) ; set free space offset INExit CLR.W D0 ; result = ok INExit1 MOVEM.L (A6)+,D1-D2/A1 ; restore registers MOVE.L (A6)+,-(SP) ; put return address back on stack TST.W D0 ; set condition codes RTS ; exit ExtInitNode ;__________________________________________________________________________________ ; ; Routine: ExtInsertRec ; ; Function: Inserts a record into a BTree node. ; ; Input: A0.L - pointer to record (to insert) ; A1.L - ptr(node buffer) ; D0.W - size of record (data + key) ; D1.W - index of insert point ; ; Output: D0.W - result code ; 0 = ok ; -1 = won't fit ; A1.L - ptr(node buffer) containing new record ; D1.W - index of new record ; ; Called by: BTInsert,ExtRotateLt,RotRecLt ;__________________________________________________________________________________ ExtInsertRec MOVEM.L D1-D7/A1-A5,-(SP) ; save regs ; ; set up some common stuff ; MOVE.W D0,D7 ; save size of record MOVE.W D1,D6 ; save insert index MOVE.L A0,D5 ; save ptr to record MOVE.W D1,D0 ; insert index JSR ExtGetOffset ; MOVE.W D0,D4 ; D4 = insert offset MOVE.W NDNRecs(A1),D0 ; number of keys = last index JSR ExtGetOffset ; MOVE.L A0,A3 ; A3 = ptr(last offset) MOVE.W D0,D3 ; D3 = last offset ; ; see if new record will fit ; MOVE.L A3,D1 ; ptr(last offset) CLR.L D0 ; MOVE.W D3,D0 ; - (last offset + node base) ADD.L A1,D0 ; SUB.L D0,D1 ; = avail space MOVEQ #2,D0 ; 2 + record size ADD.W D7,D0 ; = required size CMP.W D0,D1 ; enough space ? BGE.S IRInsert ; yes -> MOVEQ #-1,D0 ; indicate "won't fit" BRA.S IRExit ; exit ; ; make hole for new record ; IRInsert MOVE.L A1,A5 ; A5 = ptr(node buffer) LEA 0(A5,D4.W),A0 ; source = ptr(insert record) LEA 0(A0,D7.W),A1 ; dest = source + size MOVE.W D3,D0 ; last offset SUB.W D4,D0 ; - insert offset = count JSR ExtMovRecRt ; make hole for new record ; ; adjust offsets for moved records ; MOVE.L A3,A0 ; source ptr = ptr to last offset LEA -2(A0),A1 ; dest ptr = source ptr - 2 MOVE.W NDNRecs(A5),D0 ; offset count = SUB.W D6,D0 ; last index - insert index MOVE.W D7,D1 ; delta = record size JSR ExtMovOffLt ; adjust offsets left ; ; move in the new record ; MOVE.L D5,A0 ; source = ptr(record) LEA 0(A5,D4.W),A1 ; dest = ptr(insert record) MOVE.W D7,D0 ; count = record size JSR ExtMovRecLt ; move record in ADDQ.W #1,NDNRecs(A5) ; increment key count CLR.W D0 ; result = ok IRExit MOVEM.L (SP)+,D1-D7/A1-A5 ; restore regs TST.W D0 ; set condition codes RTS ; exit ExtInsertRec ;__________________________________________________________________________________ ; ; Routine: ExtLocBTCB (Locate BTree Control Block) ; ; Function: Locates the BTCB for a BTree file given the refnum. ; ; Input: D0.W - file refnum ; ; Output: A4.L - pointer to BTCB ;__________________________________________________________________________________ ExtLocBTCB ; ; locate BTCB for the file ; MOVEA.L FCBSPtr,A4 ; start of FCBS MOVEA.L FCBBTCBptr(A4,D0.W),A4 ; ptr(BTCB) RTS ; exit ExtLocBTCB ;__________________________________________________________________________________ ; ; Routine: ExtLocRec (Locate Record)) ; ; Function: Locates the key and data record for a specified BTree record. ; ; Input: A1.L - ptr(node buffer) ; D1.W - record index ; A4.L - pointer to BTCB ; ; Output: ; A0.L - ptr(key) ; A1.L - ptr(data record) ; D1.W - size of record ;__________________________________________________________________________________ ExtLocRec MOVEM.L D0/D2-D3,-(SP) ; save registers MOVE.W D1,D3 ; D3 = record index MOVE.W D3,D0 ; locate JSR ExtGetRecA ; ...the record MOVE.L A0,D2 ; D2 = ptr(record) MOVE.W D3,D0 ; locate ADDQ #1,D0 ; JSR ExtGetRecA ; ...the next record MOVE.L A0,D1 ; D1 = ptr(next record) MOVEA.L D2,A0 ; ptr(key) = ptr(record) MOVEQ #0,D0 ; get key length MOVE.B (A0),D0 ; ADDQ.L #2,D0 ; include length byte LSR.L #1,D0 ; LSL.L #1,D0 ; ...and adjust to word boundry SUB.L D2,D1 ; record size = ptr(next record) SUB.L D0,D1 ; - ptr(record) - (adj key length) MOVEA.L A0,A1 ; ptr(data record) = ptr(key) ADDA.L D0,A1 ; + (adj key length) MOVEM.L (SP)+,D0/D2-D3 ; restore registers RTS ; exit ExtLocRec ;__________________________________________________________________________________ ; ; Routine: ExtLocTPR (Locate Tree Path Record) ; ; Function: Locates the Tree Path Record (TPR) for a given tree level. ; ; Input: D0.W - tree level ; A4.L - pointer to BTCB ; ; Output: A0.L - ptr(TPR) ;__________________________________________________________________________________ ExtLocTPR SUB.W #1,D0 ; offset MULU #LenTPR,D0 ; ...from beg of table MOVEA.L BTCVarPtr(A4),A0 ; ptr to BTree buffer LEA BTVTPTable(A0,D0.L),A0 ; get ptr(TPR) RTS ;__________________________________________________________________________________ ; ; Routine: ExtMovOffLt ; ; Function: Move offsets left within a single node. ; ; Input: D0.W - number of offsets ; D1.W - delta amount to be added to each offset ; A0.L - pointer to source offset ; A1.L - pointer to destination offset ; ; Output: none ;__________________________________________________________________________________ ExtMovOffLt MOVEM.L D0-D2/A0-A1,-(SP) ; save regs @1 MOVE.W (A0)+,D2 ; *ptrDst++ = *ptrSrc++ + delta ADD.W D1,D2 MOVE.W D2,(A1)+ DBF D0,@1 BRA.S MovOExit ; return ;__________________________________________________________________________________ ; ; Routine: ExtMovOffRt ; ; Function: Move offsets right within a single node. ; ; Input: D0.W - number of offsets ; D1.W - delta amount to be added to each offset ; A0.L - pointer to source offset ; A1.L - pointer to destination offset ; ; Output: none ;__________________________________________________________________________________ ExtMovOffRt MOVEM.L D0-D2/A0-A1,-(SP) ; save regs CMPM.W (A0)+,(A1)+ ; preincrement A0, A1 for loop @1 MOVE.W -(A0),D2 ; *ptrDst-- = *ptrSrc-- + delta ADD.W D1,D2 MOVE.W D2,-(A1) DBF D0,@1 MovOExit MOVEM.L (SP)+,D0-D2/A0-A1 ; restore regs RTS ;__________________________________________________________________________________ ; ; Routine: ExtMovRecLt ; ; Function: Move records left within a single node. ; ; Input: D0.W - number of bytes to move ; A0.L - pointer to source ; A1.L - pointer to destination ; ; Output: none ;__________________________________________________________________________________ ExtMovRecLt MOVEM.L D0-D1/A0-A1,-(SP) ; save regs TST.W D0 ; test byte count BLE.S MovlExit ; byte count <= 0 SUBQ.W #1,D0 ; adjust loop index @1 MOVE.B (A0)+,(A1)+ ; move DBRA D0,@1 ; ...it MovlExit MOVEM.L (SP)+,D0-D1/A0-A1 ; restore regs RTS ; return ;__________________________________________________________________________________ ; ; Routine: ExtMovRecRt ; ; Function: Move records right within a single node. ; ; Input: D0.W - number of bytes ; A0.L - pointer to source ; A1.L - pointer to destination ; ; Output: none ;__________________________________________________________________________________ ExtMovRecRt MOVEM.L D0-D1/A0-A1,-(SP) ; save regs TST.W D0 BLE.S MovrExit ; byte count <= 0 ADDA.W D0,A0 ; high-address of source block ADDA.W D0,A1 ; high-address of dest block SUBQ.W #1,D0 ; byte count - 1 @1 MOVE.B -(A0),-(A1) ; move DBRA D0,@1 ; ...it MovrExit MOVEM.L (SP)+,D0-D1/A0-A1 ; restore regs RTS ; return ;__________________________________________________________________________________ ; ; Routine: ExtRelNode ; ; Function: Releases use of a BTree node obtained by ExtGetNode. ; Note: this is a temporary interface, it will change for the new ; cache. ; ; Input: A0.L - pointer to node buffer ; D1.B - RelBlock option flags ; A4.L - pointer to BTCB ; ; Output D0.W - result code ; 0 = ok ; -n = error ; ; Called by: BTInsert,BTDelete,BTGetRecord,BTSearch,ExtTreeSearch ;__________________________________________________________________________________ ExtRelNode MOVE.L (SP)+,-(A6) ; save return address on A6 stack MOVE.L A1,-(A6) ; save registers MOVE.L A0,D0 ; have a node to release? <23Sep85> BEQ.S @RNExit ; no -> <23Sep85> IF HFSDebug THEN ; Only check when debugging <24Sep85> TST.W NDNRecs(A0) ; empty node? <23Sep85> BEQ.S @1 ; yes, skip node check <23Sep85> MOVEA.L A0,A1 ; ***** check out the node ***** <21Sep85> BSR ExtChkNode ; <21Sep85> BEQ.S @1 ; ok -> <21Sep85> _HFSDSErr ; *** HALT *** <24Sep85> ENDIF @1 JSR ExtRelBlock ; release the block @RNExit MOVE.L (A6)+,A1 ; restore registers MOVE.L (A6)+,-(SP) ; put return address back on stack TST.W D0 ; set up condition codes RTS ; exit ExtRelNode ;__________________________________________________________________________________ ; ; Routine: ExtSearchNode ; ; Function: Searches a BTree node for a specified key. A binary search ; algorithym is used. ; ; Input: A0.L - ptr(search key) ; A1.L - ptr(node buffer) ; A4.L - pointer to BTCB ; ; Output: D0.W - result code ; 0 = ok ; BTnotfound = record not found ; A1.L - ptr(node buffer) ; D1.W - index ; record index if found ; insert index if not found ; ; Called by: BTSearch,ExtTreeSearch ;__________________________________________________________________________________ ExtSearchNode MOVEM.L D2-D5/A1-A3,-(SP) ; save regs ; ; set up some common stuff ; MOVE.L A0,A3 ; A3 = ptr(search key) MOVE.L A1,A2 ; A2 = ptr(node buffer) MOVE.L BTCKeyCR(A4),D5 ; D5 = ptr(key compare routine) ; ; search node for key using a binary search ; CLR.W D2 ; lower bnd = 0 MOVE.W NDNRecs(A2),D3 ; upper bnd = number of recs - 1 SUBQ.W #1,D3 CMP.W D3,D2 ; while lower bnd <= upper bnd BGT.S SrchExit SrchLoop MOVE.W D2,D4 ; index = (upper+lower) / 2 ADD.W D3,D4 ; LSR.W #1,D4 ; D4 = new index MOVE.W D4,D0 ; get ptr(trial key) MOVE.L A2,A1 ; JSR ExtGetRecA ; MOVE.L A0,A1 ; A1 = ptr(trial key) MOVEA.L A3,A0 ; A0 = ptr(search key) MOVE.L A4,-(SP) ; save A4 MOVEA.L D5,A4 ; A4 = ptr(key compare routine) JSR (A4) ; compare the keys MOVE.L (SP)+,A4 ; restore A4 TST.W D0 ; test result code BEQ.S SrchEQ ; search key = trial key -> BGT.S SrchGT ; search key > trial key -> SrchLT ; search key < trial key MOVE.W D4,D3 ; upper = index - 1 SUBQ.W #1,D3 CMP.W D3,D2 ; upper <= lower ? BLE.S SrchLoop BRA.S SrchExit SrchEQ CLR.W D0 ; result = FOUND BRA.S SrchRet SrchGT MOVE.W D4,D2 ; lower = index + 1 ADDQ.W #1,D2 CMP.W D3,D2 ; lower <= upper ? BLE.S SrchLoop SrchExit MOVE.W D2,D4 ; index = lower MOVEQ #BTnotfound,D0 ; result = 'not found' <14Oct85> ; ; clean up and exit ; SrchRet MOVE.W D4,D1 ; return index in D1 MOVEM.L (SP)+,D2-D5/A1-A3 ; restore regs TST.W D0 ; set up condition codes RTS ; exit ExtSearchNode ;__________________________________________________________________________________ ; ; Routine: ExtUpdDRec (Update Data Record) ; ; Function: Updates the data portion of a BTree record. ; ; Input: A0.L - ptr(data record) ; 0 = create a null record (cleared to zero) ; D0.W - size of data record ; A1.L - ptr(node buffer) containing BTree record ; D1.W - index of BTree record ; A4.L - pointer to BTCB ; ; Output: none ;__________________________________________________________________________________ ExtUpdDRec MOVEM.L D0-D1/A0-A2,-(SP) ; save registers MOVEA.L A0,A2 ; A2 = ptr(data record) JSR ExtLocRec ; locate data position in BTree record MOVE.L A2,D1 ; ptr(data record) BEQ.S @2 ; ptr = 0, clear the record -> MOVEA.L D1,A0 ; source = data record EXT.L D0 ; move length = record size _BlockMove ; move in the data record BRA.S UDExit ; all done -> @1 CLR.B (A1)+ ; clear the record @2 DBRA D0,@1 ; UDExit MOVEM.L (SP)+,D0-D1/A0-A2 ; restore registers RTS ; exit ExtUpdDRec ;__________________________________________________________________________________ ; ; Routine: ExtUpdIKey (Update Index Key) ; ; Function: Updates the key portion of an index record. Variable ; length source keys are padded with $00 to obtain a fixed ; length index key. ; ; Input: A0.L - pointer to source key ; A1.L - pointer to index record key ; A4.L - pointer to BTCB ; ; Output: A1.L - pointer to updated index record key ;__________________________________________________________________________________ ExtUpdIKey MOVEM.L D0-D1/A0-A2,-(SP) ; save regs MOVEA.L A0,A2 ; save ptr(source key) MOVE.W BTCKeyLen(A4),D1 ; get max key length MOVE.B D1,(A1)+ ; stuff max key length MOVEA.L A2,A0 ; ptr(source key) MOVEQ #0,D0 ; fixing a bug here <06Jul90> MOVE.B (A0)+,D0 ; source key length <06Jul90> ; EXT.W D0 ; this is bad for D0 >= $80 <06Jul90> SUB.W D0,D1 ; max key length - source key length BGE.S @2 ; length ok, decrement before testing -> ADD.W D1,D0 ; source > max, use max length BRA.S @2 ; @1 MOVE.B (A0)+,(A1)+ ; copy next byte @2 DBF D0,@1 ; TST.W D1 ; need any null padding? BLE.S @5 ; no -> BRA.S @4 ; decrement before testing @3 CLR.B (A1)+ ; clear next byte in key (null pad) @4 DBF D1,@3 @5 MOVEM.L (SP)+,D0-D1/A0-A2 ; restore regs RTS ; exit ExtUpdIKey END