; ; File: BTMAINT2.a ; ; Contains: These routines provide single-node BTree maintenance functions. ; ; Written by: Bill Bruffey ; ; Copyright: © 1984-1991 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; <4> 9/10/91 JSM Cleanup header. ; <3> 9/21/90 BG Removed <2>. 040s are behaving more reliably now. ; <2> 6/20/90 CCH Added some temporary NOPs to prevent pipeline problems in ; 68040's. ; <1.3> 5/4/89 KST Fixed a bug in GetMaxkey. ; 5/4/89 KSCT Fixed a bug in GetmaxKey, 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 LocBTCB from BTIntf to BTMaint2. ; 10/10/85 BB Added use of new MOVEQ equates for GetBlock and RelBlock. Added ; GetMaxKey subroutine and a call to it in BuildIRec. Did some ; minor code clean up. ; 9/26/85 BB Modified GetNode 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 Modified RelNode to handle a null node pointer and to call ; ChkNode. ; 9/23/85 BB Added ClrNode and a call to it in InitNode. ; 9/6/85 BB Fixed minor bugs in GetNodeSize and GetOffA. ; 8/29/85 BB Changed ChkNode to use a more efficient method for checking ; record offsets. ; 8/22/85 BB Added GetNode,RelNode, and ChkNode. ; 8/8/85 BB Modified GetOffset and InitNode for new node format. ; 7/31/85 BB Fixed bug in LocRec which was causing the "write" problem. ; 7/17/85 BB Added GetNodeSiz. Modified GetRecA to also return record size. ; 7/8/85 BB Modified GetLtSib/GetRtSib 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 InsertRec to return node number and record index of new ; record. ; 2/18/85 BB Modified LocRec 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 Added KeyCompare routine. ; 1/5/85 BB Changed CopyRec to LocRec to support return of key and data ; record pointers instead of copying that data. ; 1/5/85 BB Modified SearchNode to use external key compare routine. ; 10/1/84 BB Split off from BTmaint. ; ;__________________________________________________________________________________ ; ; External ; Routines: BuildIRec - Builds an index record for a specified target node. ; ChkNode - Checks the validity of a node. ; ClrNode - Clears a node (to zero). ; DeleteRec - Deletes a record from a BTree node. ; GetMaxKey - Gets max key size rounded to word boundry. ; GetNode - Gets a BTree node from disk. ; GetNodeSiz - Gets the size of the data currently contained in a ; node (record data + offset overhead). ; GetLtSib - Gets left sibling node for a given BTree node. ; GetRtSib - Gets right sibling node for a given BTree node. ; GetOffset - Gets the record offset and the pointer to the offset ; word for a given record index. ; GetRecA - Gets the address of the record for a given record ; index. ; InitNode - Gets a cache buffer for a new node and initializes it to ; an empty state. ; InsertRec - Inserts a record into a BTree node. ; LocBTCB - Locates the BTCB for a BTree file. ; LocRec - Locates the key and data records for a specified ; BTree record. ; LocTPR - Locates the Tree Path Record (TPR) for a given tree ; level. ; MovOffLt - Move offsets left within a single node. ; MovOffRt - Move offsets right within a single node. ; MovRecLt - Move records left within a single node. ; MovRecRt - Move records right within a single node. ; RelNode - Releases the use of a node. ; SearchNode - Searches a BTree node for a specified key. ; UpdDRec - Updates the data portion of a BTree record. ; UpdIKey - Updates the key portion of an index record. ; ; Internal ; Subroutines: None. ; ;__________________________________________________________________________________ BLANKS ON STRING ASIS PRINT OFF LOAD 'StandardEqu.d' PRINT ON PRINT NOGEN BTMaint2 PROC EXPORT EXPORT BuildIRec,ChkNode,ClrNode,DeleteRec EXPORT GetMaxKey,GetNode,GetNodeSiz,GetLtSib,GetRtSib,GetOffset,GetRecA EXPORT InitNode,InsertRec,LocBTCB,LocRec,LocTPR EXPORT MovOffLt,MovOffRt,MovRecLt,MovRecRt EXPORT RelNode,SearchNode,UpdDRec,UpdIKey EXPORT vGetNode,vRelNode IMPORT GetBlock,RelBlock ;__________________________________________________________________________________ ; ; Routine: BuildIRec ; ; 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 ;__________________________________________________________________________________ BuildIRec MOVE.L D2,-(SP) ; save regs MOVE.L D0,D2 ; save node number CLR.W D0 ; locate 1st record BSR GetRecA ; ...in node MOVEA.L BTCVarPtr(A4),A1 ; locate record buffer LEA BTVRecord(A1),A1 ; JSR UpdIKey ; move in the key BSR GetMaxKey ; 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 BuildIRec ;__________________________________________________________________________________ ; ; Routine: ChkNode ; ; 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: GetNode ;__________________________________________________________________________________ ChkNode 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 FCBPLen(A2,D1.W),D0 ; PEOF / node size 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 GetOffset ; 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 ChkNode ;__________________________________________________________________________________ ; ; Routine: ClrNode ; ; Function: Clears a node to all zeroes. ; ; Input: A0.L - pointer to node buffer ; A4.L - pointer to BTCB ; ; Output none ; ; Called by: BTDelete ;__________________________________________________________________________________ ClrNode 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 ClrNode <23Sep85> ;__________________________________________________________________________________ ; ; Routine: DeleteRec ; ; 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 ;__________________________________________________________________________________ DeleteRec 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 GetOffset ; 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 GetOffSet ; 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 MovRecLt ; 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 MovOffRt ; adjust the offsets DRExit MOVEM.L (SP)+,D2-D6/A2-A5 ; restore regs RTS ; return ;__________________________________________________________________________________ ; ; Routines: GetLtSib (Get Left Sibling) ; GetRtSib (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 ;__________________________________________________________________________________ GetLtSib MOVE.L (SP)+,-(A6) ; save return address on A6 stack MOVEM.L D2-D3,-(A6) ; save registers CLR.B D3 ; indicate GetLtSib BRA.S GSRtSib1 ; use common code GetRtSib MOVE.L (SP)+,-(A6) ; save return address on A6 stack MOVEM.L D2-D3,-(A6) ; save registers MOVEQ #1,D3 ; indicate GetRtSib 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 GetNode ; 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 GetLtSib/GetRtSib ;__________________________________________________________________________________ ; ; Routine: GetMaxKey ; ; 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 ;__________________________________________________________________________________ GetMaxKey MOVEQ #2,D0 ; key length = 1 <10Oct85> ; 2, include length byte <5/4/89> ADD.W BTCKeyLen(A4),D0 ; + max key length <10Oct85> LSR.W #1,D0 ; rounded down <10Oct85> LSL.W #1,D0 ; <10Oct85> RTS ; exit GetMaxKey <10Oct85> ;__________________________________________________________________________________ ; ; Routine: GetNode ; ; 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 ;__________________________________________________________________________________ GetNode MOVE.L jGetNode,-(SP) ; jumptable entry for vGetNode <25Oct85> RTS ; go there <25Oct85> vGetNode ; 'vectored' GetNode routine <25Oct85> 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 GetBlock ; get the block BNE.S GNExit ; didn't get it -> MOVEA.L A0,A1 ; verify the node BSR ChkNode ; BEQ.S GNExit ; its ok -> <26Sep85> MOVE.W D0,-(A6) ; save result code <26Sep85> MOVEQ #kRBTrash,D1 ; set trash option <10Oct85> <26Sep85> MOVEA.L BTCCQptr(A4),A1 ; ptr to cache queue <26Sep85> JSR RelBlock ; 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 GetNode ;__________________________________________________________________________________ ; ; Routine: GetNodeSiz (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 ;__________________________________________________________________________________ GetNodeSiz MOVE.L D1,-(SP) ; save registers MOVE.W NDNRecs(A1),D1 ; number of records in node MOVE.W D1,D0 ; record data size JSR GetOffset ; = 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 GetNodeSiz ;__________________________________________________________________________________ ; ; Routine: GetOffset (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 ;__________________________________________________________________________________ GetOffset 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: GetRecA (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 ;__________________________________________________________________________________ GetRecA MOVEM.L D1-D2,-(SP) ; save registers MOVE.W D0,D1 ; D1 = record index BSR.S GetOffSet ; 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 GetOffSet ; 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: InitNode ; ; 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 ;__________________________________________________________________________________ InitNode 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 GetBlock ; get cache buffer BNE.S INExit1 ; error -> ; ; initialize the node ; BSR ClrNode ; 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 InitNode ;__________________________________________________________________________________ ; ; Routine: InsertRec ; ; Function: Inserts a record into a BTree node. ; ; Input: A0.L - pointer to record ; A1.L - ptr(node buffer) ; D0.W - size of record ; 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,RotateLt,RotRecLt ;__________________________________________________________________________________ InsertRec 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 GetOffset ; MOVE.W D0,D4 ; D4 = insert offset MOVE.W NDNRecs(A1),D0 ; number of keys = last index JSR GetOffSet ; 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 MovRecRt ; 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 MovOffLt ; 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 MovRecLt ; 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 InsertRec ;__________________________________________________________________________________ ; ; Routine: LocBTCB (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 ;__________________________________________________________________________________ LocBTCB ; ; locate BTCB for the file ; MOVEA.L FCBSPtr,A4 ; start of FCBS MOVEA.L FCBBTCBptr(A4,D0.W),A4 ; ptr(BTCB) RTS ; exit LocBTCB ;__________________________________________________________________________________ ; ; Routine: LocRec (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 ;__________________________________________________________________________________ LocRec MOVEM.L D0/D2-D3,-(SP) ; save registers MOVE.W D1,D3 ; D3 = record index MOVE.W D3,D0 ; locate JSR GetRecA ; ...the record MOVE.L A0,D2 ; D2 = ptr(record) MOVE.W D3,D0 ; locate ADDQ #1,D0 ; JSR GetRecA ; ...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 LocRec ;__________________________________________________________________________________ ; ; Routine: LocTPR (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) ;__________________________________________________________________________________ LocTPR 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: MovOffLt ; ; 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 ;__________________________________________________________________________________ MovOffLt 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: MovOffRt ; ; 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 ;__________________________________________________________________________________ MovOffRt 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: MovRecLt ; ; 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 ;__________________________________________________________________________________ MovRecLt 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: MovRecRt ; ; 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 ;__________________________________________________________________________________ MovRecRt 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: RelNode ; ; Function: Releases use of a BTree node obtained by GetNode. ; 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,TreeSearch ;__________________________________________________________________________________ RelNode MOVE.L jRelNode,-(SP) ; jumptable entry for vRelNode <25Oct85> RTS ; go there <25Oct85> vRelNode ; 'vectored' RelNode routine <25Oct85> 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 ChkNode ; <21Sep85> BEQ.S @1 ; ok -> <21Sep85> _HFSDSErr ; *** HALT *** <24Sep85> ENDIF @1 JSR RelBlock ; 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 RelNode ;__________________________________________________________________________________ ; ; Routine: SearchNode ; ; 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,TreeSearch ;__________________________________________________________________________________ SearchNode 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 GetRecA ; 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 SearchNode ;__________________________________________________________________________________ ; ; Routine: UpdDRec (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 ;__________________________________________________________________________________ UpdDRec MOVEM.L D0-D1/A0-A2,-(SP) ; save registers MOVEA.L A0,A2 ; A2 = ptr(data record) JSR LocRec ; 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 UpdDRec ;__________________________________________________________________________________ ; ; Routine: UpdIKey (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 ;__________________________________________________________________________________ UpdIKey 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) MOVE.B (A0)+,D0 ; source key length EXT.W D0 ; 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 UpdIKey END