📄 dkio.asm
字号:
ADC FileDB.FD_OUTPS,0 ;add 1 if printing character
SoutExit:
cEnd ;exit
SUBTTL disk OPEN
page
;***
;DISK_OPEN -- open a file
;
;Purpose:
; Open a file. Code is in dkopen.asm.
;*******************************************************************************
DISK_OPEN EQU B$DISKOPEN
SUBTTL disk block input/output
page
;***
;DISK_BLKIN -- disk block input
;DISK_BLKOUT -- disk block output
;
;Purpose:
; Rewritten as part of revision [11].
; DISK_BLKIN - disk block input, used for BLOAD only.
; DISK_BLKOUT - disk block output, used for BSAVE only.
; File position is assumed as already set, the read
; or write will position the file to the next byte
; after the operation.
;Entry:
; (ES:)[SI] = DGROUP offset of FDB of file to be loaded/saved
; DX:BX = source (segment:offset)
; CX = maximum number of bytes to read/write
;Exit:
; CY set - error in read or write.
; clear - no error.
;Uses:
; AX,CX,DX.
;Exceptions:
; None.
;*******************************************************************************
cProc DISK_BLKOUT,<NEAR>
cBegin
MOV AH,C_WRITE ;set DOS 3 function to write file
SKIP 2 ; skip over DISK_BLKIN
cEnd nogen
cProc DISK_BLKIN,<NEAR>
cBegin
MOV AH,C_READ ;set DOS 3 function to read file
cEnd nogen
cProc DISK_BLK,<NEAR>,<BX,DS>
cBegin
PUSH FileDB.FD_HANDLE ;handle on stack while DS=DGROUP
MOV DS,DX ;set DS to segment of memory to operate upon
ASSUME DS:NOTHING
MOV DX,BX ;set to offset of memory
POP BX ;pop handle to register for call
INT 21H ;perform either DOS 3 read or write
JC DISK_BLK_ERR ;if error in operation, then jump
CMP AX,CX ;test completion - carry set if not complete
DISK_BLK_ERR:
cEnd
ASSUME DS:DGROUP
SUBTTL clear buffer
page
;***
;ClrRestBuf -- fill remainder of buffer with 0's. Added with [21].
;
;Purpose:
; Fill the remainder of buffer with 0's after a short read.
;Entry:
; [AX] = number of valid bytes in buffer
; [CX] = number of bytes to clear (# requested - # read)
; [ES:DI] = *buffer
;Exit:
; End of buffer filled with 0's
;Uses:
; CX
;Preserves:
; AX,BX,DX
;Exceptions:
; none
;*******************************************************************************
cProc ClrRestBuf,<NEAR>,<AX,CX,DI>
cBegin
ADD DI,AX ; [ES:DI] = address to start clear
XOR AX,AX ; fill with nulls
SHR CX,1 ; make length word
REP STOSW ; store word
JNC ClrBufExit ; brif no odd byte -- exit
STOSB ; store odd byte
ClrBufExit:
cEnd ; return to caller
SUBTTL random I/O supporting routine
page
;***
; B$MUL32 - 16x32 bit multiply with error checking
;
;Purpose:
;
;Entry:
; [DX:CX] = multiplicand
; [AX] = multiplier
;
;Exit:
; [DX:CX] = [DX:CX] * [AX]
;
;Uses:
; AX
;
;Preserves:
; BX
;
;Exceptions:
; B$ERR_BRN -- bad record number upon overflow
;
;******************************************************************************
cProc B$MUL32,<NEAR,PUBLIC>,BX
cBegin
xchg ax,cx ; get multiplier into cx, low word into ax
call B$Mul32x16 ; [DX|AX] = [DX|AX] * [CX]
xchg ax,cx ; [DX|CX] = result
jc ERCBRN ; brif overflow
cEnd
;***
;Locate -- locate the positon in a file
;
;Purpose:
; This routine checks whether a given record number is legal. If it is
; fine, translate it into the number of bytes.
;Entry:
; (ES:)[SI] = *FDB
; [DX|CX] = record number if user specified
; [AL] = flag
; the flag is defined as the follows:
; RELFLG ==> record number specified
;
;Exit:
; [DX|CX] = the location in bytes
; FileDB.FD_BUFCNT = 0
;Uses:
; None
;Preserves:
; AX,BX
;Exceptions:
; B$ERR_BRN -- bad record number
;*******************************************************************************
cProc Locate,<NEAR>
cBegin
TEST AL,RELFLG ;record number specified?
JZ RelRecNum ; Brif not -- use next record #
OR DX,DX ;test upper word of record
JS ERCBRN ;Brif negative, "bad record number"
JNZ RecNumOK ;Brif positive, record number is OK
JCXZ ERCBRN ;Brif low word = 0, "bad record number"
RecNumOK:
SUB CX,1 ;make it 0-relative
SBB DX,0
TEST FileDB.FD_MODE,MD_BIN+MD_RND ; random or binary?
JZ LocateExit ; brif not -- exit with [DX|CX] =
; byte offset
MOV FileDB.FD_LOGREC,CX ;save the new referred record #
MOV FileDB.FD_HIGHLR,DX
RelRecNum:
MOV CX,FileDB.FD_LOGREC ;[DX|CX] = current logical record
MOV DX,FileDB.FD_HIGHLR
TEST FileDB.FD_MODE,MD_BIN ; (SPEED) binary mode?
JNZ LocateExit ; brif so -- exit w/o multiplying
; by VRECL, since it is 1
PUSH AX ; save register
MOV AX,FileDB.FD_VRECL ;multiplier
CALL B$MUL32 ; [DX|CX] = [DX|CX] * [AX]
POP AX ; restore register
LocateExit:
MOV FileDB.FD_BUFCNT,0 ;no read/unwritten bytes in buffer
cEnd ;exit to caller
ERCBRN: JMP B$ERR_BRN ; bad record number
SUBTTL disk random I/O
page
;***
;DISK_RANDIO -- low level routine to access a file for GET/PUT
;
;Purpose:
; This routine reads from/writes to a file a record.
;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] = record length to be written
; [CX|DX] = user specified record number if GET/PUT
; (ES:)[SI] = *FDB
; [b$RECPTR] = Pointer to the data to be written
;
;Exit:
; [AX] = number of bytes actual read/write
; one buffer is filled/flushed
;Uses:
; none
;Exceptions:
; B$ERR_IOE -- device I/O error
; B$ERR_FWP -- permission denied
; B$ERR_ACD -- path/file access error
; B$ERR_BRN -- bad record number (from Locate)
;*******************************************************************************
cProc DISK_RANDIO,<NEAR>,<CX,DI>
cBegin
XCHG DX,CX
CALL Locate ;[DX|CX] = DWORD byte position of record
TEST FileDB.FD_FLAGS,FL_CHAR
JNZ GetPutCharDev ;Brif it is a character device
test al,VarStrData ; processing data of var len string?
jnz GiveDosCall ; brif so -- don't do the seek. File is
; correctly positioned past count word.
push ax ; save flags
CALL B$SeekFromStart ;seek to set file location (preserves BX)
pop ax ; restore flags
GiveDosCall: ;issue the Dos call (AL = Flags)
PUSH AX ;save flags
LES DI,[b$RECPTR] ; address of buffer
cCall DosReadWrite ;issue the Dos call, on return if CY then
; error happened, AX=error code, else
; [AX] has the actual number of
; read/write
POP DX ;get back flag in DX
JB JMP_AnalyzeErr1 ; error return
FDB_PTR ES ;freshen FDB seg
TEST FileDB.FD_MODE,MD_BIN ; binary mode?
JZ NotBin ; brif not -- don't adjust count
ADD FileDB.FD_LOGREC,AX ; add number actually read/written
JMP SHORT IsBin ; to record count
NotBin:
test dl,VarStrLen ; length of variable length string?
jnz NoIncrement ; brif not -- don't increment rec #
ADD FileDB.FD_LOGREC,1 ; increment record number
IsBin:
ADC FileDB.FD_HIGHLR,0
JS ERCBRN ; brif overflow -- bad record number
NoIncrement:
OR FileDB.FD_FLAGS,FL_NEOF ; assume no EOF
TEST DL,PUTFLG ; is put ?
JNZ PutBuf ; Brif yes
MOV CX,BX ; requested count
SUB CX,AX ; CX = number we didn't get
JCXZ GetPutExit ; Brif got all we requested
AND FileDB.FD_FLAGS,NOT FL_NEOF ;clear bit to indicate EOF
CALL ClrRestBuf ; clear rest of buffer
JMP SHORT GetPutExit ;exit
GetPutCharDev:
TEST AL,PUTFLG ; test if PUT or GET
; (bug fix -- was: NOT PUTFLG)
JZ GiveDosCall ;if GET just do the dos call
; For random char devices, LOF is just total # bytes 'PUT'
ADD FileDB.FD_FSIZ_LO,BX ; add amount to write to file size
ADC FileDB.FD_FSIZ_HI,0 ; don't bother doing overflow check.
; So what if size wraps to 0?
JMP SHORT GiveDosCall
PutBuf:
MOV CX,BX ; CX = requested count, AX = # written
CALL B$CHK_WRITE ; check if all chars written
GetPutExit:
cEnd ;exit to the caller
JMP_AnalyzeErr1:
JMP B$AnalyzeErr ; give appropriate error message
SUBTTL low level file I/O -- file access
page
;***
;DosReadWrite -- issue the DOS call for file read/write
;
;Purpose:
; Read/write a buffer via DOS call.
;Entry:
; [AL] = flag
; [BX] = Length of data to be read
; [SI] = *FDB
; [ES:DI] = *buffer
;Exit:
; b$CSRPOS = 0 (invalid) if console output.
; if CY
; [AX] = error code
; else
; [AX] = actual number of bytes read/written
; ES:[SI] = *FDB (for FV_FARFDB only)
;Uses:
; none
;Preserves: (optional)
; BX,CX,DX
;Exceptions:
; none
;*******************************************************************************
cProc DosReadWrite,<NEAR>,<BX,CX,DX>
cBegin
TEST AL,PUTFLG ;is put/write ?
MOV CX,BX ; [CX] = buffer length
MOV BX,FileDB.FD_HANDLE ; file handle
MOV DX,DI ;buffer address
JNZ DosCallWrite ;Brif PUT/WRITE
MOV AH,C_READ ;read the record in GET
SKIP 2
DosCallWrite:
MOV AH,C_WRITE ;write the record in PUT
DosCallExit:
PUSH DS ; save DS
PUSH ES
POP DS ; [DS:DX] = pointer to data
ASSUME DS:NOTHING
INT 21H ;do the call
POP DS ; restore DS
ASSUME DS:DGROUP
cEnd ;exit to caller
PAGE
;***
;B$SEEKSTART - seek to beginning of current file.
;
;Purpose:
; Added as part of revision [12].
; Seeks to beginning of file pointed to by b$PTRFIL.
; Used to back up file ptr when a Binary load has
; been detected.
;Entry:
; b$PTRFIL - points to current fdb.
;Exit:
; file ptr repositioned to beginning of current file.
;Uses:
; Per convention.
;Exceptions:
; Bad file number (from SeekToStart)
;****
cProc B$SEEKSTART,<FAR,PUBLIC>,<SI>
cBegin
FDB_PTR ES,SI,b$PTRFIL ;get FDB pointer
DbAssertRel SI,NE,0,DK_TEXT,<Invalid FDB ptr in B$SEEKSTART>
CALL SeekToStart ; seek to start of file & check for errors
cEnd
PAGE
;***
;B$BUFI, B$BUFO - Binary/Ascii Load/Save support
;
;Purpose:
; Added as part of revision [12].
; B$BUFI reads a block of data from the current file. B$BUFO writes a block
; of data to the current file. Requests for zero length reads/writes will be
; ignored. QB3 must call OPEN code to open file, followed by a call to B$CHAN
; to set the channel number. QB3 must also ensure that no heap movement occurs
; while B$BUFI and B$BUFO are active. QB3 is responsible for closing file
; (B$CLOS also clears b$PTRFIL) even if error occurs.
;
; 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:
; b$PTRFIL - contains current FDB ptr.
; stack parms:
; fpData - far pointer to data buffer.
; cbData - count of bytes to read/write.
;Exit:
; CX = 0 if CbBytes couldn't be read by B$BUFI
;Uses:
; Per convention.
;Exceptions:
; None.
;Note: Possible speed optimizations
; DosReadWrite currently CLEARS buffer before input. (could eliminate)
;
;****
cProc B$BUFI,<FAR,PUBLIC>
cBegin <nogen>
XOR AL,AL ;[AL]=I/O flag
SKIP 2 ;skip next instruction
cEnd <nogen>
cProc B$BUFO,<FAR,PUBLIC>
cBegin <nogen>
MOV AL,PUTFLG ;[AL]=I/O flag
cEnd <nogen> ;fall into BufIOCommon
cProc BufIOCommon,<FAR>,<ES,DI,SI>
parmD fpData ;ptr to IO buffer
parmW cbData ;count of bytes to read/write
cBegin
CBW ;[AX] = I/O flag
MOV CX,cbData ;[CX] = count to read/write
JCXZ BufIOExit ;brif no data to read/write
FDB_PTR ES,SI,b$PTRFIL ;get FDB pointer
LES DI,fpData ;[ES:DI] = fpData
MOV BX,CX ;[BX] = count of data to read/write
DbAssertRel SI,NE,0,DK_TEXT,<Invalid fdb ptr in B$BUFI/B$BUFO>
PUSH AX ;save I/O type
PUSH BX ;save requested byte count
CALL DosReadWrite ;do block input
POP BX ;recover requested count of bytes
JC JMP_AnalyzeErr2 ; exit if error (PSW.C set)
CMP AX,BX ;did we read 'em or writ 'em all
POP CX ;recover I/O type 0 for input.
JC BufError ;issue error
BufIOExit:
INC CX ;return CX=0 eof on read
cEnd
BufError:
JCXZ BufIEof ;EOF if couldn't read all chars
JMP B$ERR_DFL ;Disk full if output
BufIEof:
DEC CX ;make CX = FFFF so incremented to 0 for EOF
JMP SHORT BufIOExit ;return with CX=0 for eof on read
;***
; B$FLUSH - Flush the sequential output buffer. Moved here with [27].
;
;Purpose:
; Flush a buffer if it contains any data.
; No write is done unless buffer contains data
; If bit FL_TRUNC of FD_FLAGS is set (set at open time for OUTPUT files),
; a 0-length write is done before the buffer is flushed in order to set
; the file size.
;
;Entry:
; (ES:)[SI] = *FDB
;
;Exit:
; One buffer is flushed
; FileDB.FD_BUFCNT = 0
;
;Uses:
; CX
;Preserves:
; AX,BX,DX
;
;******************************************************************************
cProc B$FLUSH,<NEAR,PUBLIC>
cBegin
XOR CX,CX ; CX = 0
TEST FileDB.FD_FLAGS,FL_TRUNC ; truncate file at this time?
JZ NoTrunc ; brif not -- don't truncate file
AND FileDB.FD_FLAGS,NOT FL_TRUNC ; reset truncate flag
CALL B$FlushCount ; write 0 bytes to set file size
NoTrunc:
XCHG CX,FileDB.FD_BUFCNT ; clear count in FDB and get count in CX
JCXZ FlushExit ; if nothing in buffer, just return
cEnd nogen ; fall into B$FlushCount
;***
;B$FlushCount - Flush n bytes of the sequential output buffer.
;
;Purpose:
; Write a specified number of chars from the sequential file buffer
; without checking for a zero buffer count.
;
;Entry:
; (ES:)[SI] = *FDB
; CX = number of chars to write
;
;Exit:
; One buffer is flushed
; FileDB.FD_BUFCNT IS NOT CHANGED!
;
;Uses:
; None
;Preserves:
; All
;
;******************************************************************************
cProc B$FlushCount,<NEAR,PUBLIC> ; Rename and make public
cBegin
PUSH AX ; save registers
PUSH BX
PUSH DX
LEA DX,FileDB.FD_BUFFER ; DX = sequential access buffer address
MOV BX,FileDB.FD_HANDLE ; BX = file descriptor
CALLOS write ;write it
JB JMP_AnalyzeErr2 ;go if error
CALL B$CHK_WRITE ; check to see that we got all we requested
POP DX ; restore registers
POP BX
POP AX
FlushExit:
cEnd
JMP_AnalyzeErr2:
JMP B$AnalyzeErr ; give appropriate error message
; file forced close and FDB deallocated
; if closing flag set.
;***
;B$CLOSE -- close a file
;
;Purpose:
;
;Entry:
; [ES:]si = *FDB
; BX = handle
;
;Exit:
; File closed.
;
;Uses:
; None
;
;Preserves:
; All
;
;Exceptions:
; All those generated by B$AnalyzeErr.
;
;******************************************************************************
cProc B$CLOSE,<NEAR,PUBLIC>,<AX>
cBegin
CALLOS close,JMP_AnalyzeErr2,bx ; make sure we don't try to close
; this file again if we have error
cEnd
sEnd ;DK_TEXT
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -