📄 dvstmt.asm
字号:
;Exceptions:
; illegal file number -- B$ERR_IFN
; bad file mode -- B$ERR_BFM
; bad record number -- B$ERR_BRN
;*******************************************************************************
cProc B$PUT3,<PUBLIC,FAR>
ParmW Channel ; I2 file number
ParmD RecPtr ; far record pointer
ParmW RecLen ; i2 record length
cBegin
MOV AL,RecFlg+PutFlg; indicate this is PUT with record var
JMP SHORT RndIO3 ; do it
cEnd nogen ; exit via B$GET3
SUBTTL Relative random I/O interfaces -- B$GET4 & B$PUT4
page
;***
;B$GET4 -- get the record with record number specified to record var
;void B$GET4(I2 Channel, I4 recnum, TYP far *recptr, I2 reclen)
;
;Purpose:
; Get the record specified into user record
;
; NOTE: This routine can take a far pointer to a movable item in a heap. This
; routine cannot directly or indirectly cause heap movement.
;
;Entry:
; Parameters in stack.
; int Channel
; long int RecNum
; typ far *RecPtr
; int RecLen
;
;Exit:
;
;Note: while calling RndDsp,
; [BX] = file number (used by B$LHFDBLOC/B$LocateFDB)
; [AL] = GET + Relative flag (refer to RndDsp)
; [CX|DX] = I4 specified record number
; [SI] = record length
; [ES:DI] = Pointer to the users record
;
;Uses:
; none
;
;Exceptions:
; illegal file number -- B$ERR_IFN
; bad file mode -- B$ERR_BFM
; bad record number -- B$ERR_BRN
;*******************************************************************************
cProc B$GET4,<PUBLIC,FAR>
ParmW Channel ; I2 file number
ParmD RecNum ; I4 record number
ParmD RecPtr ; far record pointer
ParmW RecLen ; I2 record length
cBegin
MOV AL,RelFlg+RecFlg; indicate GET with record number & var
RndIO4:
MOV CX,Seg_RecNum ; CX = RecNum high
OR CX,CX ; can't be negative number
JS ERCBRN ; Brif negative, give "bad record number"
MOV DX,Off_RecNum ; DX = RecNum low
MOV BX,CX ; another copy of RecNum high in BX
OR BX,DX ; can't be zero
JZ ERCBRN ; Brif zero, give "bad record number"
MOV BX,Channel ; BX has the channel number
PUSH SI
PUSH DI
PUSH ES
MOV SI,RecLen ; [SI] = Record length
LES DI,RecPtr ; [ES:DI] = Record Pointer
cCall RndDsp ; do the work
POP ES
POP DI
POP SI
cEnd ; exit to caller
;***
;B$PUT4 -- put a record with specified record number from record var
;void B$PUT4(I2 Channel, I4 RecNum, TYP far *recptr, I2 reclen)
;
;Purpose:
; Put a record from record var with specified record number.
;
; NOTE: This routine can take a far pointer to a movable item in a heap. This
; routine cannot directly or indirectly cause heap movement.
;
;Entry:
; Parmaters in stack.
; int Channel
; long int RecNum
; typ far *RecPtr
; int RecLen
;
;Exit:
;
;Note: while calling RndDsp,
; [BX] = file number (used by B$LHFDBLOC/B$LocateFDB)
; [AL] = GET + Relative flag (refer to RndDsp)
; [CX|DX] = I4 specified record number
; [SI] = record length
; [ES:DI] = Pointer to the users record
;
;Uses:
; none
;
;Exceptions:
; illegal file number -- B$ERR_IFN
; bad file mode -- B$ERR_BFM
; bad record number -- B$ERR_BRN
;*******************************************************************************
cProc B$PUT4,<PUBLIC,FAR>
ParmW Channel ; I2 file number
ParmD RecNum ; I4 record number
ParmD RecPtr ; far record pointer
ParmW RecLen ; I2 record length
cBegin
MOV AL,RelFlg+PutFlg+RecFlg ; indicate PUT Rec Num & Rec Var
JMP SHORT RndIO4 ; do it
cEnd nogen ; exit via B$GET4
Locals PROC NEAR
SUBTTL B$FREF - Return next available file number
PAGE
;***
; B$FREF - Return next available file number
; int pascal B$FREF(void)
;
;Purpose:
; Runtime entry point to return the next available file number. This is done
; by a pretty dumb repetative linear search of all FDBs, trying all file
; numbers starting at 1. Anything more intelligent is probably more effort
; than it's worth, since the call to FREEFILE will more often than not be
; followed by an OPEN call, which is probably I/O bound.
;
;Entry:
; None.
;
;Exit:
; [AX] = Next available file number.
;
;Uses:
; Per convention.
;
;Exceptions:
; B$ERR_SSC, if the heap is screwed up.
;
;******************************************************************************
cProc B$FREF,<FAR,PUBLIC,FORCEFRAME>,<SI>
cBegin
XOR AX,AX ; [AX] = potential "next" file number
FREF_5: ; Loop to restart at beging of FDB chain
XOR SI,SI ; [SI] = Flag to get first FDB pointer
INC AX ; [AX] = next potential "next" filenumber
FREF_10: ; Loop for each FDB
CALL B$LHNXTFIL ; [SI] = pointer to next FDB
JZ FREF_90 ; Jump if no more FDB's (we're done)
CALL B$LHLOCFDB ; [BL] = filenumber associated with FDB
CMP AL,BL ; See if our "guess" is being used
JNZ FREF_10 ; loop to go check next FDB if not used
JMP FREF_5 ; else loop to attempt a new guess
FREF_90: ; FDB chain end found, and guess not used
cEnd
SUBTTL EOF interface -- B$FEOF
page
;***
;B$FEOF -- function which detects the EOF for a file
;I2 B$FEOF(I2 Channel)
;
;Purpose:
; Detect whether the EOF is reached. This function is only significant
; for a input or communication file.
;
; Note: EOF won't return true (-1) for a random file, even if you GET
; a record beyond the file end. However, that GET gets a null
; record.
;
;Entry:
; Parameter in stack.
; int Channel
;Exit:
; [AX] = -1 EOF is reached for a sequential input file, or
; communication buffer is empty
; = 0 EOF is not reached yet
;Uses:
; none
;Exceptions:
; illegal file number -- B$ERR_IFN
;*******************************************************************************
cProc B$FEOF,<PUBLIC,FAR>
ParmW Channel ;I2, file number
cBegin
MOV BX,Channel ;BX has file number
OR BX,BX ;special for standard input ?
JZ REDIR ;Brif yes
MOV AH,DV_EOF ;end of file function
cCall ComDsp ; do it, on return [AX] has the result
JMP SHORT EOFExit ;exit to caller
REDIR:
TEST b$IOFLAG,RED_INP ; is input file redirected ?
JZ ERCIFN ; Brif not, give "illegal file number"
MOV AX,C_IOCTL SHL 8 + InpSts ; get input status
INT 21h ; is the end of a file ?
;[AL] = 0FFH if not end of file
;[AL] = 0 if end of file
CBW ;result in AX
NOT AX ; and pervert
EOFExit:
cEnd ;clear stack and return
SUBTTL B$FATR - FILEATTR function
PAGE
;***
; B$FATR - FILEATTR function
; I4 pascal B$FATR(I2 channel, I2 fieldid)
;
;Purpose:
; Returns specific information from an FDB, based on the fieldid value. This
; interface allows us to muck with the FDB, and still provide the same info
; to the user in a stable fasion.
;
;Entry:
; channel = File number to be queried
; fieldid = field number to be returned
;
;Exit:
; [DX:AX] = requested information
;
;Uses:
; Per convention
;
;Exceptions:
; B$ERR_FC = Bad field number
;
;******************************************************************************
cProc B$FATR,<FAR,PUBLIC>,<SI>
parmW channel ; file to futz with
parmW fieldid ; field desired
cBegin
MOV BX,channel ; [BX] = File's channel #
cCall B$LHFDBLOC ; [SI] = FDB pointer (NZ if found)
JNZ FATR_3 ; Jump if so
JMP B$ERR_IFN ; else bad file number
FATR_3:
MOV BX,fieldid ; [BX] = user requested field
DEC BX ; Make it zero-relative
CMP BX,FIELDID_MAX ; See if in range
JB FATR_5 ; Jump if valid request
JMP B$ERR_FC ; Else illegal function call
FATR_5:
ADD BX,BX ; [BX] = word offset into table
XOR AX,AX ; Init I4 return value
CWD
FDB_PTR ES,SI,SI ;(ES:)[SI] = * FDB
ADD SI,CS:[BX].FIELDOFF_TABLE ; FDB field by fun. (zero rel)
JMP CS:[BX].FIELDDISP_TABLE ; Dispatches by fun. (zero rel)
FATR_TWO: ; Dispatch point for two byte fields
LODS WORD PTR FileDB ; Load FDB word
JMP SHORT FATR_90
FATR_ONE: ; Dispatch point for one byte fields
LODS BYTE PTR FileDB ; Load FDB byte
FATR_90:
cEnd
ERCIFN: JMP B$ERR_IFN ;illegal file number
SUBTTL general I/O supporting routines
page
;***
;ComDsp -- common dispatch routine
;
;Purpose:
; This common dispatch routine checks the legality of the channel
; and then dispatch to the actual working routine.
;Entry:
; [AH] = fucntion number (minor #)
; [BX] = file number
;Exit:
; depends on function
;Uses:
; none
;Exceptions:
; illegal file number -- B$ERR_IFN
;*******************************************************************************
cProc ComDsp,<NEAR>,<SI> ;save SI
cBegin
CALL B$LHFDBLOC ;[SI] = file data block pointer
JZ ERCIFN ;Error - illegal file number
CALL B$PtrDispatch ; dispatch to the working routine
cEnd ;pop si and exit to caller
;***
;RndDsp -- dispatch for random I/O
;
;Purpose:
; Check the legality of the file number and the file mode. If both
; OK, dispatch to the working routine.
;Entry:
; [AL] = flags
; Bit 0: 1 if PUT, else GET
; BIT 1: 1 if explicit record number specified
; BIT 2: 1 if record variable specified
; [BX] = file number
; [CX:DX] = record number if RelFlg is on. Note: use [CX|DX] here
; for the consistence with DOS function call
; [ES:DI] = record variable address, if RecFlg is on
; [SI] = record variable length, if RecFlg is on
;
;
;Exit:
; a record is in random buffer
;Uses:
; none
;Exceptions:
; illegal file number -- B$ERR_IFN
; bad file mode -- B$ERR_BFM
;*******************************************************************************
cProc VarStrLenDsp,<NEAR>,<SI,ES,DI>
cBegin
jmp VarStrLen_Entry
cEnd <nogen>
cProc RndDsp,<NEAR>,<SI,ES,DI>
cBegin
PUSH SI ; preserve record length
CALL B$LHFDBLOC ;NZ & [SI]=*FDB if file number found
POP BX ; [BX] = length of record variable
JZ ERCIFN ;Brif not found, give "illegal file number"
FDB_PTR ES,SI,SI ;(ES:)[SI] = *FDB
TEST FileDB.FD_MODE,MD_RND+MD_BIN ; random or binary?
JNZ RND_OR_BIN
JMP ERCBFM ; brif not - bad file mode
RND_OR_BIN:
TEST AL,RecFlg ; See if record variable passed
JNZ RndDsp_5 ; Jump if it was
TEST FileDB.FD_MODE,MD_BIN ; binary mode?
JZ NOT_BIN
JMP ERCRVR ; brif so -- record variable required
NOT_BIN:
PUSH DS ; Form...
POP ES ; pointer in...
LEA DI,FileDB.FD_BUFFER ;[ES:DI] ptr to record (field buffer)
MOV BX,FileDB.FD_VRECL ;[BX] = length of record (LEN= length)
JMP SHORT RndDsp_15 ; go finish dispatch
RndDsp_5: ; record variable was passed in
OR BX,BX ; 0-length read/write?
JNZ NotSD ; brif not -- not a string descriptor
; A 0-length means that we have a string
; descriptor and that we must dereference
; ES:DI = string descriptor address
TEST FileDB.FD_MODE,MD_BIN ; binary mode?
JNZ NotVarLenStr ; brif so -- no special string handling
; Special code to handle puts/gets from/into variable-length strings.
; For random files, the length of the string will be placed in the file
; before the string data.
push ax ; save flags
push cx ; save optional record #
push dx
mov bx,2 ; length to read/write
or al,VarStrLen ; don't increment record # after next op.
test AL,PutFlg ; PUT statement?
jnz PutStrLen ; brif so -- output length
; GET statement
;(othewise, ES should be equal to ds/ss)
push bx ; save '2'
push di ; save SD offset
push ax ; space for length on stack
mov di,sp ; ES:DI = addr of length word
call VarStrLenDsp ; read length of string into ES:DI
pop ax ; AX = length to read (new str length)
pop di ; DI = SD offset
pop bx ; BX = 2 (total # to read)
FDB_PTR ES,si,si ; restore (ES:)[SI] = *FDB for ChkRandom
add bx,ax
call ChkRandom ; do verification
push ax ; save length
cCall B$STDL,<DI> ; deallocate existing string
pop cx ; restore CX = length
jcxz RestoreState ; brif zero-length string -- don't do ALLOC
mov bx,cx ; BX = new string length
call B$STALC ; alloc string with new length, BX=*str data
mov [di],cx ; set SD string length
mov [di+2],bx ; set SD string address
mov [bx-2],di ; set back pointer
jmp short RestoreState
PutStrLen: ; PUT statement, DS:[DI] = str len (from SD)
push bx ; save '2'
add bx,[di] ; bx = 2+string length
call ChkRandom ; do verification
pop bx ; restore bx = 2
call VarStrLenDsp ; write length of string to file
RestoreState:
pop dx ; restore optional record #
pop cx
pop ax ; restore flags
or al,VarStrData ; don't seek before next get/put
NotVarLenStr:
MOV BX,ES:[DI] ; BX = string length
MOV DI,ES:[DI+2] ; DS:DI = string address
PUSH DS ; ES:DI = string address
POP ES
OR BX,BX ; null string?
JZ RndExit ; brif so -- return without doing anything
FDB_PTR ES ;restore FDG SEG in ES
NotSD:
TEST FileDB.FD_MODE,MD_BIN ; binary mode?
JNZ RndDsp_15 ; brif so -- skip checks for bad record
; length and field statement
VarStrLen_Entry:
call ChkRandom
RndDsp_15:
MOV [b$RECPTR],DI
MOV [b$RECPTR+2],ES ; [b$RECPTR] = record pointer
MOV AH,DV_RANDIO ;AH=function number (minor #)
CALL B$PtrDispatch ; dispatch to the working routine
RndExit:
cEnd ;pop si, exit to caller
;***
;ChkRandom -- verify stuff before RANDOM file I/O
;
;Purpose:
; Added with revision [43] to save code.
;
;Entry:
; BX = length to read/write (includes count word for variable-length
; strings as record variables).
;Exit:
; None
;Uses:
; None
;Preserves:
; All
;Exceptions:
; Bad record length, Field statement active
;
;******************************************************************************
cProc ChkRandom,<NEAR>
cBegin
CMP BX,FileDB.FD_VRECL ; record too long?
JA ERCBRL ; brif so -- Bad record length
TEST FileDB.FD_FLAGS,FL_FIELD ; FIELD stmt active for this FDB?
JNZ ERCFSA ; brif so -- FIELD statement active
cEnd
ERCBRL: JMP B$ERR_BRL
ERCFSA: JMP B$ERR_FSA
; FIELDOFF_TABLE
;
; Table of FDB fields offsets that FILEATTR will return. Each entry contains
; the location within the FDB of the field to be returned.
;
; FIELDDISP_TABLE
; table of routine offsets to execute to fetch a particular field.
;
labelW FIELDOFF_TABLE
DW FD_MODE ; 1: File Mode
DW FD_HANDLE ; 2: DOS file handle
labelW FIELDDISP_TABLE
DW FATR_ONE ; 1: File Mode: one byte
DW FATR_TWO ; 2: DOS file handle: two byte
FIELDID_MAX = 2 ; last entry in table
Locals ENDP
ERCBFM: JMP B$ERR_BFM ;bad file mode
ERCRVR: JMP B$ERR_RVR ;record variable required
sEnd ;DV_TEXT
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -