Category : Files from Magazines
Archive   : BYTE0389.ZIP
Filename : ZSAM.ASM

 
Output of file : ZSAM.ASM contained in archive : BYTE0389.ZIP



; ***************************************************
; * ZSAM - Z-DOS KEYED SEQUENTIAL ACCESS METHOD *
; * Copyright 1988 by R. GREHAN, BYTE MAGAZINE *
; * >>> 8088 version <<< *
; * >>> Interfaces to Borland's Turbo C <<< *
; * You may use this product for educational, non- *
; * commercial use only. *
; ***************************************************
;
;
; *** FUNCTION CODES FOLLOW
; 0 - REWIND 6 - WRITE DATA REC
; 1 - READ KEY RECORD 7 - APPEND DATA REC
; 2 - READ NEXT KEYED REC. 8 - DELETE KEYED REC
; 3 - READ NEXT DATA REC 9 - DELETE KEY
; 4 - CREATE KEYED REC 10 - DELETE DATA REC
; 5 - INSERT KEY 11 - REWIND DATA REC SET

; *** ERROR CODES
ERR_KNF EQU 200 ;KEY NOT FOUND
ERR_KAE EQU 201 ;KEY ALREADY EXISTS
ERR_EOF EQU 202 ;END OF FILE
ERR_EOS EQU 203 ;END OF RECORD SET
ERR_EMF EQU 204 ;EMPTY FILE
ERR_RSD EQU 205 ;RECORD SET DELETED
ERR_DPI EQU 206 ;DATA POINTER INVALID
ERR_KPI EQU 207 ;KEY POINTER INVALID
ERR_FNZ EQU 208 ;FILE NOT ZSAM
ERR_DNC EQU 209 ;DATA FILE NOT COMPLEX
ERR_SOV EQU 210 ;STACK OVERFLOW
;
KNODE_LEN EQU 512 ;Key node length for this version

DOSSEG ;Order segments acc'd to Intel
.MODEL SMALL ;Use Small Model
;
; Though this version of ZSAM is meant to work with small-model
; TURBO-C, it does have all the necessary code (I hope!) to allow
; for the caller to use a separate data segment. So, ZSAM
; puts the caller's data segment into ES and the local data
; segment in DS.
;
; **********************
; * Uninitialized data *
; **********************
.DATA?
;
; >>> LOCAL STORAGE <<<
; KEY FILE Header
KFTYPE DB ? ;Key file type
;"K"=Standard key file
;"O"=Keyonly file
ROOTSC DW ? ;Root sector number
NOKEYSL DW ? ;Number of keys in index file
NOKEYSH DB ?
KAVSEC DW ? ;Head of key avail list
NXKYSC DW ? ;Next free key sector in file
KEYLEN DB ? ;Keylength
MAXKS DB ? ;Max no. keys per sector
ACKYSC DW ? ;Actual key sector
CUKYSC DW ? ;Current key number
CUKYOF DB ? ;Current key offset
IFLAG DB ? ;At interstice flag
STKCNT DB ? ;Stack count
PSTACK LABEL WORD ;Word access to pseudo stack
PSTACKB DB 40 DUP (?) ;Pseudo stack
KSPAC EQU $-OFFSET KFTYPE
;
; DATA FILE Header
DFTYPE DB ? ;Data file type
;"S"=Simple data file
;"C"=Complex data file
RECLEN DW ? ;Record length
NORECSL DW ? ;Number of records in file
NORECSH DB ?
DAVLO DW ? ;Available list
DAVHI DB ?
NXDALO DW ? ;Next free record
NXDAHI DB ?
DRINTF DB ? ;Data rec interstice flag
CUDALO DW ? ;Current sector
CUDAHI DB ?
HDDALO DW ? ;Head record
HDDAHI DB ?
TLDALO DW ? ;Tail record
TLDAHI DB ?
FWPTLO DW ? ;Forward pointer
FWPTHI DB ?
BKPTLO DW ? ;Back pointer
BKPTHI DB ?
DSPAC EQU $-OFFSET DFTYPE
;
; TRANSFER
; ZSAM IS CALLED WITH err = zsam(zp); where zp = *zpacket;
; struct zpacket {
; int funct;
; char *keybuf;
; char *datbuf;
; char *key;
; char *rec;
; char *keyhead;
; char *dathead;
; }

PACKSIZ EQU 14 ;Structure size
FUNCT DW ? ;Function number
KBFPTR DW ? ;Key file buffer pointer
DBFPTR DW ? ;Data file buffer pointer
KEYPTR DW ? ;Key$ pointer
RECPTR DW ? ;Rec$ pointer
KTRANPTR DW ? ;Pointer to keyfile header inf.
DTRANPTR DW ? ;Pointer to datafile header inf.
;
; WORKING STORAGE
ERRNO DW ? ;Error code
SPLTFG DB ? ;Split flag
INSTFG DB ? ;Insert flag
POPSC DW ? ;Popped sector for delete
POPKYOF DB ? ;Popped offset for delete
FLTKYBFW LABEL WORD
FLTKYBF DB 72 DUP (?) ;Floating key buffer
KEYCNT DB ? ;Key count
WORKYW LABEL WORD
WORKY DB 574 DUP (?) ;Working key buffer
PACKPTR DW ? ;Packet pointer holding

;*******************
; Initialized data
;*******************
.DATA
;
; JUMP VECTOR TABLE
JVECTS DW OFFSET REWF ;Rewind file
DW OFFSET READKR ;Read keyed record
DW OFFSET READNKR ;Read next keyed record
DW OFFSET READNDR ;Read next data record
DW OFFSET CRKY ;Create keyed record
DW OFFSET CRKY ;Insert key
DW OFFSET WRITEDR ;Write data record
DW OFFSET APPENDR ;Append data record
DW OFFSET DELEKR ;Delete keyed record
DW OFFSET DELE ;Delete key
DW OFFSET DELEDR ;Delete data record
DW OFFSET REWDR ;Rewind data set

.CODE
;
; External functions
EXTRN _zgetks:PROC
EXTRN _zputks:PROC
EXTRN _zgetdr:PROC
EXTRN _zputdr:PROC

;
; ***************************************
; * FOLLOWING IS THE OUTER ROUTINE THAT *
; * HANDLES THE ENTRY TO AND EXIT FROM *
; * ZSAM. *
; ***************************************
PUBLIC _zsam
_zsam PROC
PUSH BP ;**For C **
MOV BP,SP ;Get stack ptr
PUSH ES ;Save their ES
PUSH SI ;..and SI
PUSH DI ;..and DI
MOV AX,DS
MOV ES,AX ;Their DS is our ES
;**ADD CODE HERE TO INITIALIZE LOCAL DATA
;**SEGMENT IF NECESSARY.
MOV SI,[BP+4] ;Structure pnter - source
MOV PACKPTR,SI
MOV DI,OFFSET FUNCT ;Dest.
MOV CX,PACKSIZ ;# bytes
MOV DX,ES ;Swap ES,DS
MOV BX,DS
MOV ES,BX
MOV DS,DX
REP MOVSB
MOV ES,DX ;Restore
MOV DS,BX
; Get transfer information. First look at FUNCT and see
; how much to actually transfer
MOV AX,FUNCT
CMP AL,3 ;RD NEXT DATA?
JE ZSAM0
CMP AL,6 ;WRITE DATA?
JE ZSAM0
CMP AL,7 ;APPEND DATA?
JE ZSAM0
CMP AL,10 ;DELETE DATA?
JGE ZSAM0
MOV SI,KTRANPTR ;Source
MOV DI,OFFSET KFTYPE ;Dest.
MOV CX,KSPAC ;# bytes
MOV DS,DX ;Swap ES & DS again
MOV ES,BX
REP MOVSB
MOV DS,BX
MOV ES,DX
JMP SHORT ZSAM0A
;Set KTRANPTR to -1 to show we don't need to send anything back
ZSAM0: MOV WORD PTR KTRANPTR,0FFFFH
;Transfer data file information (if data file is used)
ZSAM0A: CMP BYTE PTR KFTYPE,'O'
JE ZSAM1 ;Jump if not
CMP AL,0 ;REWIND?
JE ZSAM1
CMP AL,9 ;DELETE KEY?
JE ZSAM1
MOV SI,DTRANPTR ;Source
MOV DI,OFFSET DFTYPE ;Dest.
MOV CX,DSPAC
MOV DS,DX ;Swap ES & DS again!
MOV ES,BX
REP MOVSB
MOV DS,BX
MOV ES,DX
JMP SHORT ZSAM2
; Set DTRANPTR to -1 to show we don't need to send data file info
; back to the caller.
ZSAM1: MOV WORD PTR DTRANPTR,0FFFFH
;Vector to routine
ZSAM2: MOV WORD PTR ERRNO,0 ;Clear any old errors
MOV BX,FUNCT ;Get function
ADD BX,BX ;Byte addr
CALL CS:WORD PTR JVECTS[BX]
;All done - go home
; Do we need to send key info back?
MOV DI,KTRANPTR
INC DI ;DI=FFFF?
JZ ZSAM3 ;Jump if no info
DEC DI
MOV SI,OFFSET KFTYPE
MOV CX,KSPAC
REP MOVSB
; Do we need to send data info back?
ZSAM3: MOV DI,DTRANPTR
INC DI ;DI=FFFF?
JZ ZSAM4 ;Jump if no info
DEC DI
MOV SI,OFFSET DFTYPE
MOV CX,DSPAC
REP MOVSB
; Send back error code
ZSAM4: MOV AX,ERRNO
MOV BX,ES
MOV DS,BX ;Put back DS
POP DI ;...and other saved regs
POP SI
POP ES
POP BP
RET ;Small model short return
_zsam ENDP
;
; ****************************************
; * REWIND KEY FILE MAIN ROUTINE *
; ****************************************
REWF PROC NEAR
XOR AX,AX ;Clear AX
MOV CUKYOF,AL ;Zero key pointer
MOV CUKYSC,AX ;Zero sector
MOV STKCNT,AL ;Zero stack
RET
REWF ENDP
;
; ****************************************
; * REWIND DATA REC SET MAIN ROUTINE *
; ****************************************
REWDR PROC NEAR
; Must be a complex data file
CMP BYTE PTR DFTYPE,'C'
JZ REWDR1
MOV WORD PTR ERRNO,ERR_DNC
RET
;Set current to head and turn on data int. flag
REWDR1: MOV AL,HDDAHI
MOV CUDAHI,AL
MOV AX,HDDALO
MOV CUDALO,AX
MOV BYTE PTR DRINTF,1
RET
REWDR ENDP
;
; ****************************************
; * READ KEYED RECORD MAIN ROUTINE *
; ****************************************
READKR PROC NEAR
CALL SRCH ;Look for the key
CMP WORD PTR ERRNO,0 ;Found?
JZ READKR1
XOR AX,AX
MOV CUDALO,AX ;Show invalid data
MOV CUDAHI,AL
RET
READKR1: CMP BYTE PTR KFTYPE,'O' ;Keyonly file?
JE READKRX ;Skip data record read
CALL RDDATAR ;Read data record
READKRX: RET ;Go home
READKR ENDP
;
; ****************************************
; * READ NEXT KEYED RECORD MAIN ROUTINE *
; ****************************************
READNKR PROC NEAR
CALL SSK ;Seek successor
CMP WORD PTR ERRNO,0 ;Hit eof?
JZ READNKR1
;Show invalid data
XOR AX,AX
MOV CUDALO,AX
MOV CUDAHI,AL
RET
;Copy the key into into zsam->key
READNKR1: CALL CALKYO ;Get key offset
MOV SI,BX ;In SI
ADD SI,KBFPTR ;Source
MOV DI,KEYPTR ;Dest.
MOV CL,KEYLEN ;# bytes
XOR CH,CH
PUSH DS ;DS=ES
PUSH ES
POP DS
REP MOVSB
POP DS ;Restore
;Read data record
CMP BYTE PTR KFTYPE,'O' ;Keyonly file?
JE READNKRX ;Skip data read if so.
CALL RDDATAR
READNKRX: RET
READNKR ENDP
;
; *****************************************
; * READ NEXT DATA RECORD MAIN ROUTINE *
; *****************************************
READNDR PROC NEAR
;Make sure we have a complex data file
CMP BYTE PTR DFTYPE,'C'
JZ READNDR1
MOV WORD PTR ERRNO,ERR_DNC
RET
;Check for valid data pointer
READNDR1: MOV AL,CUDAHI
XOR AH,AH
OR AX,CUDALO
JNZ READNDR2
MOV WORD PTR ERRNO,ERR_DPI
RET
;See if we are at interstice -- just clear DRINTF if so
READNDR2: MOV AH,FWPTHI ;Get forward link
MOV BX,FWPTLO
CMP BYTE PTR DRINTF,0
JE READNDR3
MOV BYTE PTR DRINTF,0
JMP SHORT READNDR5
;Looks ok -- fetch next record if possible
READNDR3: OR AH,AH ;Are we at tail?
JNZ READNDR5
OR BX,BX
JNZ READNDR5
;We are at end of set - do a rewind
CALL REWDR
MOV WORD PTR ERRNO,ERR_EOS
RET
;Passed all tests -- read the record
READNDR5: CALL RDCDATR
RET
READNDR ENDP
;
; ***************************************
; * APPEND DATA RECORD MAIN ROUTINE *
; ***************************************
APPENDR PROC NEAR
; Must be complex data file
CMP BYTE PTR DFTYPE,'C'
JZ APPENDR1
MOV BYTE PTR ERRNO,ERR_DNC
RET
; Ok - do append - find a free data record
APPENDR1: CALL FREDT
; Now set up record -- fix link information first
MOV SI,OFFSET FWPTLO
XOR AX,AX
MOV [SI],AX ;End of set marker
MOV [SI+2],AL
MOV AX,TLDALO
MOV WORD PTR [SI+3],AX
MOV AL,TLDAHI
MOV BYTE PTR [SI+5],AL
MOV CX,6 ;# bytes
MOV AH,CUDAHI
MOV BX,CUDALO
PUSH AX
PUSH BX ;Save
XOR AL,AL ;Offset 0
MOV DX,DS ;Our segment
CALL WDATR ;Write pointer info
;Pointer info written - now write the data record
POP BX ;Restore record number
POP AX
MOV AL,6 ;Offset past pointers
MOV SI,RECPTR
MOV DX,ES ;Caller's segment
MOV CX,RECLEN ;# of bytes
CALL WDATR
;Fix links - tail first
MOV BX,TLDALO
MOV CX,CUDALO
MOV TLDALO,CX
MOV AH,TLDAHI
MOV CL,CUDAHI
MOV TLDAHI,CL
MOV CX,3 ;Only writing a pointer
PUSH CX
MOV SI,OFFSET CUDALO
PUSH SI
XOR AL,AL ;Offset 0
MOV DX,DS ;Our segment
CALL WDATR
;Now fix head
MOV AH,HDDAHI
MOV BX,HDDALO
POP SI ;Restore buffer
POP CX ;Restore count
MOV DX,DS
MOV AL,3 ;Offset 3 within record
CALL WDATR
;Now set inter flag

MOV BYTE PTR DRINTF,0 ;Show at record
RET
APPENDR ENDP
;
; ****************************************
; * WRITE DATA RECORD MAIN ROUTINE *
; ****************************************
WRITEDR PROC NEAR
; Make sure we have a valid data pointer
CMP BYTE PTR DRINTF,0
JNZ WRITEDR1
MOV AH,CUDAHI
MOV BX,CUDALO
OR AH,AH
JNZ WRITEDR2
OR BX,BX
JNZ WRITEDR2
WRITEDR1: MOV WORD PTR ERRNO,ERR_DPI
RET
;Data pointer valid -- check file type
WRITEDR2: XOR AL,AL ;Assume simple
CMP BYTE PTR DFTYPE,'S'
JZ WRITEDR3
;Complex file type
MOV AL,6 ;Offset for complex file
WRITEDR3: MOV SI,RECPTR ;Data
MOV CX,RECLEN ;# bytes
MOV DX,ES ;Segment
CALL WDATR ;Do it
WRITEDR4: RET
WRITEDR ENDP
;
;
; ****************************************
; * DELETE KEYED RECORD MAIN ROUTINE *
; ****************************************
DELEKR PROC NEAR
; First delete the key
CALL DELE
; See if key delete was successful
CMP WORD PTR ERRNO,0
JE DELEKR1
RET
; Ok -- see what kind of file
DELEKR1: CMP BYTE PTR DFTYPE,'C'
JZ DELEKR2
; Simple file type -- just return data record to avail list
CALL RDAVL
RET
; Complex file type -- delete record set
DELEKR2: CALL DELERS
RET
DELEKR ENDP
;
; ****************************************
; * DELETE DATA RECORD MAIN ROUTINE *
; ****************************************
DELEDR PROC NEAR
;First check for complex file type
CMP BYTE PTR DFTYPE,'C'
JE DELEDR0
MOV WORD PTR ERRNO,ERR_DNC
RET
; Now make sure we have a valid data pointer
DELEDR0: CMP BYTE PTR DRINTF,0
JNZ DELEDRA
MOV AL,CUDAHI
XOR AH,AH
MOV CX,AX
MOV BX,CUDALO
OR AX,BX
JNZ DELEDRB
DELEDRA: MOV WORD PTR ERRNO,ERR_DPI
RET
;See if we are about to delete the first guy
DELEDRB: MOV AX,CX
CMP AL,HDDAHI
JZ DELEDRC
DELDRJP: JMP DELEDR2
DELEDRC: CMP BX,HDDALO
JNZ DELDRJP
;It is first -- see if also last
CMP AL,TLDAHI
JNZ DELEDR1
CMP BX,TLDALO
JNZ DELEDR1
;We are deleting last record in set -- delete the entire
;record set and return a RECORD SET DELETED error.
CALL DELERS
MOV WORD PTR ERRNO,ERR_RSD
RET
;Not deleting entire set -- move second record into first
;and delete second
DELEDR1: PUSH BX
PUSH AX ;Save current
MOV BX,FWPTLO
MOV AH,FWPTHI
MOV DI,OFFSET WORKY ;Use working key
PUSH DI ;Save
MOV CX,RECLEN
PUSH CX ;Save
MOV AL,6 ;Offset 6
MOV DX,DS ;Segment
CALL RDATR
POP CX ;Restore count
POP SI ;Restore offset
POP AX ;Get current
POP BX
MOV AL,6
MOV DX,DS
CALL WDATR
MOV AX,FWPTLO ;Set up for normal delete
MOV CUDALO,AX
MOV AL,FWPTHI
MOV CUDAHI,AL
CLD
MOV SI,OFFSET WORKY
MOV DI,OFFSET FWPTLO
MOV CX,6
PUSH ES
PUSH DS
POP ES ;DS=ES
REP MOVSB
POP ES
; Return record to avail list -- save current
DELEDR2: MOV AX,FWPTLO
PUSH AX ;Save current
MOV AL,FWPTHI
PUSH AX
CALL RDAVL
;FiX pointer of preceding record
MOV SI,OFFSET FWPTLO
MOV DX,DS
MOV CX,3
MOV BX,BKPTLO
MOV AH,BKPTHI
XOR AL,AL
CALL WDATR
;Fix pointer of following record
MOV SI,OFFSET BKPTLO
MOV DX,DS
MOV CX,3
MOV AH,FWPTHI
MOV BX,FWPTLO
MOV AL,3 ;Offset of 3
CALL WDATR
;Reset current -- set DRINTF
POP AX
MOV CUDAHI,AL
POP BX
MOV CUDALO,BX
MOV BYTE PTR DRINTF,1
;Did we kill tail record?
CMP AL,TLDAHI
JNZ DELEDR3
CMP BX,TLDALO
JNZ DELEDR3
;We did -- new tail is BWPT
MOV AX,BKPTLO
MOV TLDALO,AX
MOV AL,BKPTHI
MOV TLDAHI,AL
XOR AX,AX
MOV CUDALO,AX
MOV CUDAHI,AL
MOV WORD PTR ERRNO,ERR_EOS
;Go home
DELEDR3: RET
DELEDR ENDP
;
; ****************************************
; * DELETE RECORD SET *
; ****************************************
DELERS PROC NEAR
;Attach current avail list to tail.
MOV SI,OFFSET DAVLO
MOV DX,DS ;Our segment
MOV CX,3 ;Write 1 pointer
XOR AL,AL ;Offset 0 into record
MOV BX,TLDALO ;Record is current
MOV AH,TLDAHI
CALL WDATR
;Head is now start of list
MOV AX,HDDALO
MOV DAVLO,AX
MOV AL,HDDAHI
MOV DAVHI,AL
;Show we no longer have a current data record
XOR AX,AX
MOV CUDALO,AX
MOV CUDAHI,AL
;Decrement number of records
SUB WORD PTR NORECSL,1
SBB BYTE PTR NORECSH,0
RET
DELERS ENDP
;
; ****************************************
; * SEEK KEY ROUTINE *
; ****************************************
;
SRCH PROC NEAR
MOV AX,NOKEYSL ;Get # keys
OR AL,NOKEYSH
OR AH,AL
JNZ SRCH1
; Empty file
MOV WORD PTR ERRNO,ERR_EMF ;Set error
CALL REWF ;Rewind
RET ;Go home
; File not empty
SRCH1: XOR AL,AL ;Clear AL
MOV STKCNT,AL
MOV IFLAG,AL ;Clear stack
MOV AX,ROOTSC ;Get root sector
SRCH2: MOV CUKYSC,AX ;Move 'er in!
CALL GETKS ;Get key sector
; Scan current key page
CALL QSCKP
JNZ SRCH3 ;No match?
RET
; Come here if no match
SRCH3: CALL CALKYO ;Calc. key off. (in BX)
ADD BX,KBFPTR ;Pointer to key buff.
MOV AX,ES:[BX-2]
OR AX,AX ;Zero?
JNZ SRCH4
; Pointer empty
MOV BYTE PTR IFLAG,1
MOV WORD PTR ERRNO,ERR_KNF
RET
; Seek down tree
SRCH4: PUSH AX ;Save pointer
CALL PUSHS ;Push pseudo stack
POP AX
CMP WORD PTR ERRNO,ERR_SOV ;Stack overflow?
JNZ SRCH2
RET ;Return if stack overflow
SRCH ENDP
;
; ****************************************
; * SEEK INORDER SUCCESSOR KEY ROUTINE *
; ****************************************
;
SSK PROC NEAR
MOV AX,NOKEYSL ;Get # keys
OR AL,NOKEYSH ;Empty?
OR AL,AH
JNZ SSK1
; Empty file - set error
MOV WORD PTR ERRNO,ERR_EMF
CALL REWF ;Rewind file
RET
; File not empty - see if rewound
SSK1: MOV AX,CUKYSC ;Get curr. key sect
OR AX,AX ;Zero?
JNZ SSK2 ;Jump if not
MOV AX,ROOTSC
JMP SHORT SSK6
;
SSK2: CALL GETKS ;Get the key sector
SSK2A: MOV BL,IFLAG ;Check interstice
OR BL,BL
JZ SSK5
; Roving pointer is at a key pointer - last one?
MOV BX,KBFPTR
MOV AH,ES:[BX] ;Get keycount
CMP AH,CUKYOF ;Last key pointer?
JZ SSK4
; Not last - point to next key
MOV BYTE PTR IFLAG,0
RET
; Last key pointer - try to pop
SSK4: CALL POPS
JZ SSK7 ;Stack empty?
JMP SHORT SSK2
; At key - incr. to next pointer
SSK5: INC BYTE PTR CUKYOF ;Incr. offset
MOV BYTE PTR IFLAG,1
SSK5A: CALL CALKYO ;Cal. offset (BX)
MOV SI,KBFPTR
MOV AX,ES:[BX+SI-2] ;Get pointer
; See if next pointer zero
OR AX,AX
JZ SSK2A ;Yup
PUSH AX ;Save keypointer
CALL PUSHS ;Push pseudo stack
POP AX ;Restore keypointer
CMP WORD PTR ERRNO,ERR_SOV ;Stack oveflow?
JNZ SSK6
RET
SSK6: MOV BYTE PTR CUKYOF,0
MOV BYTE PTR IFLAG,1
MOV CUKYSC,AX ;Set sector
CALL GETKS ;Go git it
JMP SHORT SSK5A
; EOF - Rewind
SSK7: CALL REWF ;Rewind
MOV WORD PTR ERRNO,ERR_EOF
RET
SSK ENDP

;***********************************************
;* CREATE KEY ROUTINE *
;***********************************************
CRKY PROC NEAR
MOV BYTE PTR SPLTFG,0 ;Clear split flag
;See if file is empty
MOV AX,NOKEYSL ;See if # keys 0
OR AL,NOKEYSH
OR AL,AH
JNZ CRKY1
;File empty - make a root
CALL FREKY ;Get a free key page
MOV AX,CUKYSC
MOV ROOTSC,AX ;New root
JMP SHORT CRKY2
;File not empty - search for key
CRKY1: CALL SRCH ;Search
MOV AX,ERRNO ;Get errorcode
CMP AX,ERR_KNF ;Key not found?
JZ CRKY2
CMP AX,ERR_SOV ;Stack overflow?
JZ CRKY1A ;Bail out if so.
;Key found or some other error
OR AX,AX
JNZ CRKY1A
MOV WORD PTR ERRNO,ERR_KAE
MOV CUDALO,AX ;Clear data ptr
MOV CUDAHI,AL
CRKY1A: RET
;Key not found - proceed with create
CRKY2: CALL LODKY ;Move key into floating buff.
ADD WORD PTR NOKEYSL,1
ADC BYTE PTR NOKEYSH,0 ;Increment number of keys
;If keyonly file or insert function - skip having to create
;a data record.
CMP BYTE PTR KFTYPE,'O' ;Keyonly file?
JNZ CRKY2B
CRKY2A: JMP CRKY7
CRKY2B: CMP WORD PTR FUNCT,5 ;Insert?
JZ CRKY2A
;Set up data
CALL FREDT ;Get a free data page
ADD WORD PTR NORECSL,1 ;Increment # of records
ADC BYTE PTR NORECSH,0
XOR AX,AX
CMP BYTE PTR DFTYPE,'S'
JE CRKY3
;Complex data file -- write out the pointers.
MOV FWPTLO,AX
MOV FWPTHI,AL
MOV BX,CUDALO
MOV TLDALO,BX
MOV HDDALO,BX
MOV BKPTLO,BX
MOV AH,CUDAHI
MOV TLDAHI,AH
MOV HDDAHI,AH
MOV BKPTHI,AH
MOV SI,OFFSET FWPTLO
MOV CX,6
MOV DX,DS
CALL WDATR ;Write out pointers
MOV AL,6
;Now write data record
CRKY3: MOV SI,RECPTR
MOV CX,RECLEN
MOV BX,CUDALO
MOV AH,CUDAHI
MOV DX,ES
CALL WDATR
;Move offsets to floating buffer
CRKY7: MOV SI,2+OFFSET FLTKYBF
MOV AL,KEYLEN
CBW
ADD SI,AX
MOV AX,CUDALO
MOV [SI],AX
MOV AL,CUDAHI
MOV [SI+2],AL
;Move key buffer to working key buffer
CRKY8: CALL BUTOWO
PUSH ES ;Save
PUSH DS
POP ES ;ES==DS
;Insert key - first open gap
MOV AL,WORKY
MOV KEYCNT,AL ;Save key count
CALL CALKYO ;Calc key offset
SUB BX,2 ;Pnt to leftkeypntr
MOV CX,KNODE_LEN
SUB CX,BX ;Count in CX
ADD BX,OFFSET WORKY ;Source in BX
PUSH BX ;Save for later
MOV SI,BX
MOV AL,KEYLEN
ADD AL,5
CBW
ADD BX,AX ;Calc dest.
MOV DI,BX ;Set up
STD ;Decrement pointers
ADD SI,CX ;Fixup pointers
DEC SI
ADD DI,CX
DEC DI
REP MOVSB
;Put key in gap
MOV SI,OFFSET FLTKYBF ;Source
POP DI ;Dest
MOV CL,KEYLEN
ADD CL,7 ;# bytes
XOR CH,CH
CLD ;Direction now increment
REP MOVSB
;Incr keycount
INC BYTE PTR KEYCNT
POP ES ;Restore ES
;Did we overrun?
MOV AL,KEYCNT
CMP AL,MAXKS
JA CRKY8A ;No split
JMP CRKY11
;Overrun has occured, must split
;Get center key
CRKY8A: MOV BYTE PTR SPLTFG,1 ;Set flag
SHR AL,1 ;Keycount/2
MOV CUKYOF,AL
CALL CALKYO ;Get offset
PUSH BX
ADD BX,OFFSET WORKY ;True addr
MOV SI,BX
MOV DI,2+OFFSET FLTKYBF ;Dest.
MOV AL,KEYLEN
ADD AL,3
CBW
MOV CX,AX ;Count
PUSH ES ;Save again
PUSH DS
POP ES
CLD
REP MOVSB
POP ES ;Restore
;Set leftkeypointer to current sector
MOV AX,CUKYSC ;Get sector
MOV FLTKYBFW,AX
;Fix new keycount
MOV AL,KEYCNT
SHR AL,1
MOV WORKY,AL
;Move working buffer out
CALL WOTOBU
CALL PUTKS ;Put key sector
;Create a new key sector
CALL FREKY
;Mov sector no. to rightkey pointer of floating buff
MOV BL,KEYLEN
XOR BH,BH
ADD BX,5+OFFSET FLTKYBF
MOV AX,CUKYSC
MOV [BX],AX
;Move new sector to buffer
POP SI ;Source
MOV AL,KEYLEN
ADD AL,3
CBW
ADD SI,AX ;Source addr
MOV CX,574
SUB CX,SI
ADD SI,OFFSET WORKY
MOV DI,KBFPTR
INC DI ;Skip past count
CLD
REP MOVSB
;Save new keycount
MOV AL,KEYCNT
SHR AL,1 ;keycnt/2
JC CRKY9 ;Odd?
DEC AL
CRKY9: MOV DI,KBFPTR
MOV ES:BYTE PTR [DI],AL ;Save it
CALL PUTKS ;Put key sector
;Try to pop
CALL POPS
JZ CRKY10
;You can - load sector & do this again
CALL GETKS
JMP CRKY8
;Unable to POP - make a root
CRKY10: CALL FREKY ;Create a free key page
MOV AX,CUKYSC
MOV ROOTSC,AX ;Set new root sector
JMP CRKY8

;Exit - save increment
CRKY11: MOV AL,KEYCNT
MOV WORKY,AL
CALL WOTOBU ;Move to buffer
MOV WORD PTR ERRNO,0 ;Clear error
CALL PUTKS ;Write mod. sector
;See if split occured
MOV AL,SPLTFG
OR AL,AL
JZ CRKY12
CALL SRCH ;Do search
RET
;No split - not on interstice
CRKY12: MOV BYTE PTR IFLAG,0
RET
CRKY ENDP

;***********************************************
;* DELETE KEY ROUTINE MAIN ALGORITHM *
;***********************************************
DELE PROC NEAR
;Is file empty?
MOV AX,NOKEYSL
OR AL,NOKEYSH
OR AL,AH
JNZ DELE1
;
MOV WORD PTR ERRNO,ERR_EMF
RET
;Is the key on the current sector?
DELE1: MOV AX,CUKYSC
OR AL,CUKYOF
OR AL,AH
JZ DELE2
CALL GETKS
CALL QSCKP
JZ DELE2A
DELE2: CALL SRCH ;Oh, well, do a search
CMP WORD PTR ERRNO,0 ;Found?
JZ DELE2A
RET
DELE2A: SUB WORD PTR NOKEYSL,1
SBB BYTE PTR NOKEYSH,0
;Get data record info.
CALL GETDAPO
PUSH BX
ADD BX,KBFPTR
PUSH BX ;Save for later

MOV AX,ES:[BX]
MOV CUDALO,AX ;Get data sector
MOV AL,ES:[BX+2]
MOV CUDAHI,AL ;Get data offset
;Look at left and right keypointer-see if either is zero.
;If so, we're at leaves and we're ok. Else we've gotta do tricky stuff
DELE3: POP SI ;Retrieve data ptr
DELE3A: ADD SI,3
MOV BX,ES:[SI] ;Right pointer
SUB SI,5
MOV AL,KEYLEN
CBW
SUB SI,AX
MOV AX,ES:[SI] ;Left pointer
OR AX,AX
JZ DELE4
OR BX,BX
JZ DELE4
JMP DELE8
;One or both pointers zero-merge. Then squash key node at left
;key pointer.
DELE4: OR AX,BX ;Pointer in AX
DELE4A: MOV ES:[SI],AX ;Put back in left
ADD SI,2 ;Point to key
;Squash the key
POP DI
ADD DI,5
MOV BX,KBFPTR
DELE4B: MOV AH,ES:[DI+BX]
MOV ES:[SI],AH
INC SI
INC DI
CMP DI,512
JNE DELE4B
DEC BYTE PTR ES:[BX] ;Decr. # of keys
JNZ DELE6
;All keys removed from sector. Save leftmost keypointer, pop up a level,
;and stick it in father node.
MOV AX,ES:[BX+1]
PUSH AX
CALL RKYAV ;Put sector on avail list
MOV AX,NOKEYSL ;File empty?
OR AL,NOKEYSH
OR AL,AH
JZ DELE5
;Not empty-try to pop
CALL POPS
JZ DELE5 ;Jump if unable
CALL GETKS ;Get DAD
CALL CALKYO ;Calc offset
ADD BX,KBFPTR ;Get true address
POP AX ;Get saved ptr
MOV ES:[BX-2],AX ;Store
CALL PUTKS ;Restore
JMP SHORT DELE5A
;File empty or at root
DELE5: POP AX ;Get saved ptr
MOV ROOTSC,AX
;Set pointers
DELE5A: CALL SRCH
MOV WORD PTR ERRNO,0 ;Clear error
RET
;Keys NOT all removed from sector. See if we can coalesce
DELE6: MOV AL,MAXKS
SHR AL,1 ;Maxkeys/2
MOV AH,ES:[BX] ;# keys on node
CALL PUTKS ;Write back out
CMP AH,AL
JGE DELE5A
;Sector IS candidate for coalesce-pop and check
MOV KEYCNT,AH ;Save keycount
CALL POPS ;Pop to father
JZ DELE5A ;At root-forget it
MOV AX,CUKYSC
MOV POPSC,AX ;Save father sector
CALL GETKS ;Get father
CALL BUTOWO ;Save in working buff
;Check left sibling
CMP BYTE PTR CUKYOF,0 ;At leftmost?
JZ DELE6A
DEC BYTE PTR CUKYOF
CALL CHK_COA
JZ DELE7
;Check right sibling
INC BYTE PTR CUKYOF
DELE6A: MOV AL,BYTE PTR WORKY ;Get keycount
CMP AL,CUKYOF ;At rightmost?
JNZ DELE6B
DELE6X: JMP DELE5A ;Give up
DELE6B: CALL CHK_COA
JNZ DELE6X
;OK!! Cukyof points to father to coalesce-first get left sibling
DELE7: MOV AL,CUKYOF
MOV POPKYOF,AL ;Save offset
CALL CALKYO
ADD BX,OFFSET WORKY
MOV AX,[BX-2] ;Left sibling
PUSH AX ;Save for later
PUSH BX ;Save offset
MOV CUKYSC,AX
CALL GETKS
POP SI
PUSH SI
MOV DI,KBFPTR
MOV AL,ES:[DI]
MOV CUKYOF,AL
CALL CALKYO
ADD DI,BX ;Calc. true dest.
MOV CL,KEYLEN
XOR CH,CH
CLD
REP MOVSB
;Get right sibling
POP BX ;Get offset
MOV AL,KEYLEN
CBW
ADD BX,AX
ADD BX,3
MOV AX,[BX]
MOV CUKYSC,AX
CALL BUTOWO ;Left to working
CALL GETKS
;Attach right sibling
MOV SI,KBFPTR
MOV CL,ES:[SI]
PUSH CX
INC SI ;Source
INC BYTE PTR CUKYOF
CALL CALKYO
SUB BL,2 ;Back up to pointer
ADD BX,OFFSET WORKY ;Dest
MOV DI,BX
MOV CUKYOF,CL
CALL CALKYO ;Calc true length
MOV CX,BX
DEC CX
MOV DX,ES ;Swap DS and ES
MOV BX,DS
MOV ES,BX
MOV DS,DX
REP MOVSB ;And move
MOV ES,DX
MOV DS,BX
POP AX ;Restore count
ADD AL,BYTE PTR WORKY
INC AL
MOV BYTE PTR WORKY,AL ;New byte count
;Put right sibling on avail
CALL RKYAV
;Move out left sibling
CALL WOTOBU
POP AX
PUSH AX
MOV CUKYSC,AX
CALL PUTKS
;Restore father node, delete DAD and repeat
MOV AX,POPSC
MOV CUKYSC,AX
CALL GETKS
MOV AL,POPKYOF
MOV CUKYOF,AL
CALL CALKYO
MOV SI,BX
SUB SI,2
ADD SI,KBFPTR
POP AX
CALL GETDAPO
PUSH BX
JMP DELE4A
;
;Neither pointer zero - replace key with inorder successor
DELE8: CALL BUTOWO ;Save in working buffer
MOV AX,CUKYSC ;Get current sector
PUSH AX ;And save
CALL CALKYO ;Calc offset
ADD BX,OFFSET WORKY ;True address of key
PUSH BX ;Save upcoming dest.
; Find inorder successor
CALL SSK
; Move successor to deleted slot
CALL CALKYO ;Get offset
MOV SI,KBFPTR
ADD SI,BX ;Source
POP DI ;Dest.
MOV CL,KEYLEN ;# bytes
ADD CL,3
XOR CH,CH
MOV DX,ES ;Move from caller's segment to...
MOV BX,DS ;...ours.
MOV ES,BX
MOV DS,DX
REP MOVSB ;Move it.
MOV ES,DX
MOV DS,BX
; Rotate working & key buffer
CALL ROT
; Write out modified sector
MOV AX,CUKYSC
POP BX
PUSH AX
MOV CUKYSC,BX
CALL PUTKS
; Rotate again
POP AX
MOV CUKYSC,AX
CALL ROT
; Set pointers and reenter to handle removal of inorder successor
CALL GETDAPO
MOV SI,KBFPTR
ADD SI,BX
JMP DELE3A
DELE ENDP
;
; **********************************************
; * VARIOUS AND USEFUL SUBROUTINES *
; **********************************************
;

;
; RDDATAR - READ IN A DATA RECORD
;
RDDATAR PROC NEAR
CALL GETDAPO ;Get data pointer
ADD BX,KBFPTR ;Set it up
MOV AH,ES:[BX+2] ;Get CUDAHI
MOV CUDAHI,AH
MOV HDDAHI,AH
MOV BX,ES:[BX]
MOV HDDALO,BX
MOV CUDALO,BX
CMP BYTE PTR DFTYPE,'S' ;Simple data file?
JE RDDATAR1
; Complex data file - this is head record, so set the pointers
CALL RDCDATR ;Read complex
MOV AX,BKPTLO ;Set tail pointer
MOV TLDALO,AX
MOV AL,BKPTHI
MOV TLDAHI,AL
MOV BYTE PTR DRINTF,0 ;Not at interstice
RDDATARX: RET
; Simple data file
RDDATAR1: MOV CX,RECLEN ;# Bytes
MOV DX,ES ;Segment
MOV DI,RECPTR
XOR AL,AL
CALL RDATR
RET
RDDATAR ENDP
;
; RDCDATR - Read complex data record
;
RDCDATR PROC NEAR
PUSH AX
PUSH BX ;Save
;First read the pointer information
MOV CX,6 ;Read 6 bytes
MOV DX,DS ;Our segment
MOV DI,OFFSET FWPTLO ;Buffer
XOR AL,AL ;Offset 0 of record
CALL RDATR ;Read pointers
POP BX ;Restore
POP AX
MOV DX,ES ;His segment
MOV DI,RECPTR ;His buffer
MOV AL,6 ;Skip pointers
MOV CX,RECLEN ;Read entire record
CALL RDATR ;Read
RET
RDCDATR ENDP
;
; CALKYO - Calculate a key's true byte offset (given CUKYOF).
; Result in BX.
;
CALKYO PROC
PUSH AX ;Save AX
MOV AL,KEYLEN
ADD AL,5 ;Overhead
MUL CUKYOF
ADD AX,3 ;Init. offset
MOV BX,AX ;Into BX
POP AX ;Restore
RET
CALKYO ENDP
;
; LOAD KEY INTO FLOATING KEY BUFFER
;
LODKY PROC NEAR
MOV DI,OFFSET FLTKYBF ;Source
MOV CX,72
CALL FILLZ ;Clear out buffer
MOV CL,KEYLEN
XOR CH,CH
;Now set up pointers
MOV SI,KEYPTR ;Source
MOV DI,OFFSET FLTKYBF+2 ;Destination
CLD
;Swap ES and DS
PUSH ES
PUSH DS
POP ES
POP DS
REP MOVSB
PUSH ES
PUSH DS
POP ES
POP DS
RET
LODKY ENDP
;
; READ DATA RECORD
; AH = Hi byte of record to read
; BX = Lo word of record to read
; AL = Offset into record to read from
; CX=# OF BYTES
; DX = SEGMENT OF MEMORY TO READ
; DI = OFFSET OF MEMORY TO READ
; ** SI is preserved
RDATR PROC NEAR
PUSH SI ;Save SI
PUSH ES ;Save ES
PUSH CX ;Save count for later
PUSH DX ;Save segment, too.
PUSH CX ;Push count
MOV CL,AH
XOR CH,CH
PUSH CX ;Push Hi
PUSH BX ;Push Lo
XOR AH,AH
PUSH AX ;Push offset
MOV AX,RECLEN
;If the file is complex, add 6 to record length
CMP BYTE PTR DFTYPE,'C'
JNZ RDATR1
ADD AX,6
RDATR1: PUSH AX
CALL _zgetdr ;Get the data record
ADD SP,10 ;Clear stack
POP DX ;Restore segment
POP CX ;Restore count
POP ES ;Restore ES
MOV SI,DBFPTR ;Source address
PUSH DS ;Save DS
MOV AX,ES
MOV DS,AX
MOV ES,DX
CLD
REP MOVSB ;Copy the stuff
MOV ES,AX ;Restore
POP DS
POP SI ;Restore
RET
RDATR ENDP
;
; WRITE DATA RECORD
; AH = Hi byte of record to write
; BX = Lo word of record to write
; AL = Offset into record to write from
; CX=# OF BYTES
; DX = SEGMENT OF MEMORY TO WRITE
; SI = OFFSET OF MEMORY TO WRITE
; ** DI is preserved
WDATR PROC NEAR
PUSH DI ;Protect from C
PUSH ES
;First copy stuff into data buffer
MOV DI,DBFPTR
PUSH CX ;Save count
PUSH DS
MOV DS,DX
REP MOVSB
POP DS
MOV DL,AH
XOR DH,DH
PUSH DX ;Record hi part
PUSH BX ;Record Lo part
XOR AH,AH
PUSH AX ;Record offset
MOV AX,RECLEN ;Record length
;If file is complex, add 6 to record length
CMP BYTE PTR DFTYPE,'C'
JNE WDATR1
ADD AX,6
WDATR1: PUSH AX
CALL _zputdr ;Do the write
ADD SP,10 ;Clear stack
POP ES ;Restore ES
POP DI ;Restore DI
RET
WDATR ENDP
;
; CHK_COA
; Check to see if we can coalesce. Assume father node is
; in WORKY area, and CUKYOF points to father key.
; Returns AX=0 if coalesce is possible, else returns AX<>0
;
CHK_COA PROC NEAR
MOV DI,KBFPTR ;Get key buff pointer
; First check right sibling
CALL GETDAPO ;Point to data
ADD BL,3 ;Get right key pointer
MOV AX,WORKYW[BX]
OR AX,AX ;Pointer zero?
JZ COAFL ;Fail if so
MOV CUKYSC,AX
PUSH BX ;Save BX
CALL GETKS ;Get sibling
POP BX ;Restor BX
MOV AL,ES:[DI] ;Get keycount
SUB BL,5 ;Back up to left...
SUB BL,KEYLEN ;...key pointer
MOV CX,WORKYW[BX] ;Get it
OR CX,CX
JZ COAFL
MOV CUKYSC,CX
CALL GETKS
ADD AL,ES:[DI] ;Add in count
INC AL
CMP AL,MAXKS
JLE COAOK ;Awright!
COAFL: OR AL,1 ;Show fail
RET
COAOK: XOR AX,AX
RET
CHK_COA ENDP
;
; QSCKP - Quick scan of current key page.
; This routine searches a key node for an instance of zsam->key.
; Either finds it, or returns location of where it WOULD have
; been.
;
QSCKP PROC NEAR
MOV AX,DS ;Save DS
MOV BP,ES ;Save ES
XOR CH,CH ;Clear for later
CLD ;Direction is incr.
MOV BX,KBFPTR
MOV DL,ES:[BX] ;Get keycount
MOV BYTE PTR CUKYOF,0 ;Init at leftmost
MOV BYTE PTR IFLAG,0
; Scan
QSCKP2: CALL CALKYO ;Calc key offset
MOV SI,KBFPTR ;Get pointer
ADD SI,BX ;Addr of key
MOV DI,KEYPTR ;Get zsam->key addr
MOV CL,KEYLEN ;Get key length
MOV DS,BP ;DS now ES too
REPZ CMPSB ;Compare
MOV DS,AX ;Restore DS
JZ QSCKP5
QSCKP3: JNC QSCKP4
; Come here if KEY$>KEY(CUKYOF)
INC BYTE PTR CUKYOF ;Bump offset
DEC DL ;Dec count
JNZ QSCKP2
; At end of node or at interstice
QSCKP4: OR BYTE PTR IFLAG,1
QSCKP5: RET
QSCKP ENDP
;
; Push Pseudo stack
;
PUSHS PROC NEAR
PUSH SI ;Save
MOV AL,STKCNT ;Get stack count
CMP AL,40 ;Past limit?
JZ PUSHE ;Stack full error
CBW ;Sign extend
MOV SI,AX
MOV AX,CUKYSC ;Sector
MOV PSTACK[SI],AX ;Push sector
MOV AL,CUKYOF ;Offset/flag
MOV AH,IFLAG ;Interstice
MOV PSTACK+2[SI],AX
;Push
MOV AX,SI
ADD AX,4 ;Incr. stack ptr
MOV STKCNT,AL ;New pointer
POP SI
RET
;Stack overflow error.
PUSHE: MOV WORD PTR ERRNO,ERR_SOV
POP SI
RET
PUSHS ENDP
;
; Pop pseudo stack
;
POPS PROC NEAR
XOR AH,AH
MOV AL,STKCNT
OR AL,AL ;Empty?
JNZ POPS1
RET ;Exit if so
POPS1: SUB AL,4 ;Pop stack
CBW ;Sign extend
PUSH SI ;Save
MOV STKCNT,AL ;Set new
MOV SI,AX
MOV AX,PSTACK[SI] ;Get sector
MOV CUKYSC,AX
MOV AX,PSTACK+2[SI]
MOV CUKYOF,AL ;Offset/flag
MOV IFLAG,AH
POP SI
OR AH,1 ;Show not zero
RET
POPS ENDP
;
; Get offset to data pointer
;
GETDAPO PROC NEAR
CALL CALKYO ;Point to key
PUSH AX ;Save AX
MOV AL,KEYLEN ;Get key lenght
CBW ;Word align
ADD BX,AX ;Add keylength
POP AX ;Restore
RET
GETDAPO ENDP

;
; MOVE KEY BUFFER TO WORKING BUFFER
; Assumes even number of bytes in buffer.
;
BUTOWO PROC NEAR
MOV SI,KBFPTR ;Source
MOV DI,OFFSET WORKY ;Destination
MOV CX,KNODE_LEN/2 ;Length
CLD
PUSH ES ;Swap ES and DS
PUSH DS
POP ES
POP DS
REP MOVSW
PUSH ES
PUSH DS
POP ES
POP DS
RET
BUTOWO ENDP
;
; MOVE WORKING BUFFER TO KEY BUFFER
;
WOTOBU PROC NEAR
MOV SI,OFFSET WORKY ;Source
MOV DI,KBFPTR ;Destination
MOV CX,KNODE_LEN/2 ;Length
CLD
REP MOVSW
RET
WOTOBU ENDP
;
; ROTATE KEY BUFFER AND WORKING KEY BUFFER
;
ROT PROC NEAR
MOV SI,OFFSET WORKY
MOV DI,KBFPTR
MOV CX,KNODE_LEN/2
ROT1: MOV AX,DS:[SI]
MOV DX,ES:[DI]
MOV DS:[SI],DX
MOV ES:[DI],AX
INC SI
INC SI
INC DI
INC DI
LOOP ROT1
RET
ROT ENDP
;
; GETKS - GET A KEY SECTOR
;
GETKS PROC NEAR
PUSH AX
PUSH ES
MOV AX,CUKYSC ;Sector number
CMP AX,ACKYSC ;Already in?
JZ GETKSX
PUSH AX
MOV ACKYSC,AX
CALL _zgetks ;Jump back
POP AX ;Clear stack
GETKSX: POP ES ;Restore ES
POP AX ;Restore AX
RET
GETKS ENDP
;
; PUTKS - Write a key sector
;
PUTKS PROC NEAR
PUSH AX
PUSH ES
MOV AX,CUKYSC
MOV ACKYSC,BP ;Set actual sector
PUSH AX
CALL _zputks
POP AX ;Fix stack
POP ES
POP AX
RET
PUTKS ENDP
; FIND A FREE DATA PAGE
; *** SHOULD BE MADE SMART TO SEE FULL DISK ***
;
FREDT PROC NEAR
MOV CL,DAVHI
XOR CH,CH
MOV AH,CL
OR CX,DAVLO
JZ FREDT1
;Avail list not empty
MOV BX,DAVLO
MOV DI,OFFSET DAVLO ;Read-to offset
MOV DX,DS ;Read-to segment
MOV CX,3 ;3 bytes
CALL RDATR
RET
;Avail list empty -- add new record to file
FREDT1: MOV BX,NXDALO ;Set current
MOV CUDALO,BX
MOV CL,NXDAHI
MOV CUDAHI,CL
ADD BX,1
ADC CL,0
MOV NXDALO,BX
MOV NXDAHI,CL
RET
FREDT ENDP
;
; RETURN DATA RECORD TO AVAIL LIST
;
RDAVL PROC NEAR
MOV DX,DS ;Write-from segment
MOV SI,OFFSET DAVLO ;Write-from offset
MOV CX,3 ;3 Bytes
MOV AH,CUDAHI ;Write current data record
MOV BX,CUDALO
XOR AL,AL ;Offset 0 into record
CALL WDATR
MOV AX,CUDALO ;Attach links
MOV DAVLO,AX
MOV AL,CUDAHI
MOV DAVHI,AL
RET
RDAVL ENDP
;
; FIND A FREE KEY NODE
;
FREKY PROC NEAR
MOV AX,KAVSEC ;Get avail list
MOV DI,KBFPTR
OR AX,AX ;List empty?
JZ FREKY2
;Pull off list
MOV CUKYSC,AX ;Set sector
CALL GETKS ;Get it
MOV AX,ES:[DI] ;Get avail link
MOV KAVSEC,AX ;Set it
;Clear the buffer
FREKY1: MOV CX,KNODE_LEN
FREKY1A: MOV ES:BYTE PTR [DI],0
INC DI
LOOP FREKY1A
MOV BYTE PTR CUKYOF,0
MOV BYTE PTR IFLAG,1
RET
;Get next sector ***THIS SHOULD CHECK DISK SPACE ***
FREKY2: MOV AX,NXKYSC
INC WORD PTR NXKYSC ;Bump
MOV CUKYSC,AX
JMP SHORT FREKY1
FREKY ENDP
;
; RETURN A KEY SECTOR TO THE AVAIL LIST
;
RKYAV PROC NEAR
MOV AX,KAVSEC ;Get avail sector
MOV BX,KBFPTR ;Point to buffer
MOV ES:[BX],AX ;Set up link
CALL PUTKS ;Write out sector
MOV AX,CUKYSC
MOV KAVSEC,AX ;Attack link
RET
RKYAV ENDP
;
; Fill a buffer with zeroes.
; DI - Buffer CX - Count
;
FILLZ PROC NEAR
FILLZ1: MOV BYTE PTR [DI],0
INC DI
LOOP FILLZ1
RET
FILLZ ENDP
;
END