📄 dkopen.asm
字号:
TITLE DKOPEN - DISK OPEN routines
;***
; DKOPEN - Disk open and other utility routines
;
; Copyright <C> 1986, Microsoft Corporation
;
;Purpose:
;
; The routines in this module are used while opening files
; in all modes (disk and device files).
;
;******************************************************************************
INCLUDE switch.inc
INCLUDE rmacros.inc ; general runtime macros
UseSeg _BSS
UseSeg RT_TEXT
UseSeg ER_TEXT
UseSeg NH_TEXT
UseSeg DV_TEXT
UseSeg _DATA
INCLUDE seg.inc ; Segment definitions
INCLUDE baslibma.inc
INCLUDE files.inc
INCLUDE devdef.inc
INCLUDE rtps.inc ; constants shared with QBI
INCLUDE nhutil.inc
INCLUDE string.inc
INCLUDE idmac.inc
.xall
.radix 10
;************************************************************************
;
sBegin _BSS
externB b$FILMOD
externB b$PATHNAM
externW b$Buf2
PATH_LEN EQU b$Buf2
globalW b$CLOS_HANDLE,0 ; file handle for B$TEST_CLOSE to close
globalW b$CLOS_FDB,0 ; FDB for B$TEST_CLOSE to close the file
; and deallocate the FDB.
externB b$LOCKTYPE
externB b$ACCESS
sEnd _BSS
;
;************************************************************************
;************************************************************************
;
sBegin ER_TEXT
externNP B$ERR_AFE
externNP B$ERR_BFM
externNP B$ERR_FNF
externNP B$ERR_ACD
externNP B$ERR_TMF
externNP B$ERR_IOE
externNP B$ERR_FAO
externNP B$ERR_PNF
sEnd ER_TEXT
;
;************************************************************************
;************************************************************************
;
sBegin NH_TEXT
externNP B$LHALC_CPCT ; compact LH and allocate entry
externNP B$LHDALC ; deallocate FDB
externNP B$STDALCTMP
sEnd NH_TEXT
sBegin DV_TEXT
externNP B$DOS3CHECK
externNP B$OPENIT
sEnd DV_TEXT
sBegin RT_TEXT
externNP B$GETEXTERR ; Get extended error, if available
externNP B$CLOSE
externNP B$LHNXTFIL
externNP B$FILESIZE
externNP B$SeekFromStart
externNP B$DISK_SINP
externNP B$OpenErr
;
;************************************************************************
assumes cs,RT_TEXT
SUBTTL disk OPEN
page
;***
; B$DISKOPEN - DISK device-dependent OPEN routine.
;
;Purpose:
; This routine does the actual opening of the files.
; It tries to open the file in the mode specified and
; if that fails it will then try to reopen the file
; in some of the other modes. (The reopen does not
; happen if the first try was for READ_ONLY).
; It also checks to see if it opened a character
; device and if so sets the appropriate fields in the
; FDB to reflect this. If the open is in the append mode
; it seeks to the end of the file and backs up over the
; first CTRL Z.
;
;Entry:
;
; AX = output from B$GET_PATHNAME
; BX = file number
; CX = record size
; DX = file name string descriptor (ignored)
;
;Exit:
; File opened and FDB filled in OR
; appropriate error message given.
;
;Uses:
; AX, BX, CX, DX
;
;****
cProc B$DISKOPEN,<NEAR,PUBLIC>,<ES,DI>
cBegin
PUSH DS ; ES = DS
POP ES
; First, allocate FDB with extra space for all disk files and
; space for the field buffer for random files.
INC CX ; LEN specified?
LOOP LEN_SPEC ; brif so -- use specified record length
MOV CX,REC_LENGTH ; CX = default random record length
TEST b$FILMOD,MD_RND ; random mode?
JNZ LEN_SPEC ; brif so -- use random default
MOV CX,SEQ_BUF_LEN ; use default sequential buffer length
LEN_SPEC:
TEST b$FILMOD,MD_BIN ; BINARY mode?
JZ NOT_BIN ; brif not -- keep specified buffer size
MOV CX,1 ; buffer size = 1
NOT_BIN:
PUSH CX ; save buffer size
PUSH BX ; save file number
PUSH AX ; save output from B$GET_PATHNAME
MOV DI,OFFSET DGROUP:b$PATHNAM ; DI = pathname address for
; B$CHKFOPEN
XOR SI,SI ; clear SI for B$AnalyzeErr, so it doesn't
; try to access a non-existing FDB.
; If the file is not random or sequential input, check if
; the file has been already opened in BASCOM. If CF = 1, then
; give FILE ALREADY OPEN error.
TEST b$FILMOD,MD_RND+MD_SQI+MD_BIN ; random or binary or seqin?
JNZ DOPEN_NOCHK ;if so, then jump
cCALL B$CHKFOPEN ; check if already open -- give
; "file already open" error if so
DOPEN_NOCHK:
; Determine the initial file access for the open. The accesses
; attempted are based on the file mode and ACCESS clause type:
; [b$FILMOD] = MD_SQI (sequential input)
; [b$ACCESS] = ACCESS_NONE read
; [b$ACCESS] = ACCESS_READ read
; [b$FILMOD] = MD_SQO (sequential output)
; [b$ACCESS] = ACCESS_NONE write
; [b$ACCESS] = ACCESS_WRITE write
; [b$FILMOD] = MD_RND OR MD_BIN (random or binary) [13]
; [b$ACCESS] = ACCESS_NONE read/write, write, read
; [b$ACCESS] = ACCESS_READ read
; [b$ACCESS] = ACCESS_WRITE write
; [b$ACCESS] = ACCESS_READ_WRITE read/write
; [b$FILMOD] = MD_APP (append)
; [b$ACCESS] = ACCESS_NONE read/write, write
; [b$ACCESS] = ACCESS_WRITE write
XOR BX,BX ;assume 0 for OPEN read
CMP [b$ACCESS],ACCESS_READ ;test if ACCESS READ
JE DOPEN_OPEN ;if so, jump to open file
CMP b$FILMOD,MD_SQI ; test if input sequential
JE DOPEN_OPEN ;if so, jump to open file
INC BX ;assume 1 for OPEN write
CMP [b$ACCESS],ACCESS_WRITE ;test if ACCESS WRITE
JE DOPEN_OPEN ;if so, jump to open file
CMP b$FILMOD,MD_SQO ; test if output sequential
JE DOPEN_OPEN ;if so, jump to open file
INC BX ;otherwise, read/write file
; The file is opened with the mode in BX. It is either
; opened initially in the mode computed above, or reopened
; in the next mode determined from the above table after
; an open failure.
;
; File
;-----------------------------------------------
; | doesn't | exists | OpenFlag
; | exist | | in HEX
;-----------------------------------------------
;sqi | fail | open file | 01
;sqo | create | replace | 12
;rnd | create | open file | 11
;-----------------------------------------------
;
DOPEN_OPEN:
MOV DI,BX ;save mode for possible reopen
CALL DiskOpenHelper ; open file with mode in BX
; AX = error code if error
; BX = file handle
JC OPEN_FAILED ; brif open failed
; The OPEN succeeded. The only error condition that could
; occur is if a file is to be appended with only a write
; access. If this is so, close the file and fake a
; PATH/FILE ACCESS ERROR.
CMP b$FILMOD,MD_APP ; test if append mode
JNE JMP_DOPEN_PROCESS ; brif not -- process open
CMP DI,1 ;test if WRITE access
JNE JMP_DOPEN_PROCESS ; brif not -- process open
CALL DO_CLOSE ; file is append with write mode and
;exists cannot be accessed...
JMP SHORT ERCACD ; path/file access error
; The OPEN failed. If mode was sequential input, either give
; correct access error (PERMISSION DENIED if sharing conflict
; or PATH/FILE ACCESS ERROR if directory access conflict) or
; FILE NOT FOUND.
OPEN_FAILED:
CMP AX,ERRPNF ;test if PATH NOT FOUND error
JE ERCPNF ;if so, then report it
CMP b$FILMOD,MD_SQI ; test if input sequential
JNE DOPEN_NOT_SQI_FAIL ;if not, then jump
CMP AX,ERRACD ; test if access error
JE DOPEN_ACCESS_ERROR ;if so, jump to process it
ERCFNF:
JMP B$ERR_FNF ;jump to FILE NOT FOUND
ERCPNF:
JMP B$ERR_PNF ; jump to PATH NOT FOUND
DOPEN_NOT_SQI_FAIL:
CMP AX,ERRFNF ; test if FILE NOT FOUND
JNE DOPEN_NEXT_ACCESS ;else error forces next one
MOV DX,OFFSET DGROUP:b$PATHNAM ; address of file pathname
XOR CX,CX ;attributes - none
MOV AH,C_CREAT ;create file function
CALLOS ;and make the DOS call
; AX = error code or handle
JC DOPEN_CREATE_ERROR ; if creation error, jump
XCHG BX,AX ; get handle in BX
CALL DO_CLOSE ; close the file
MOV BX,DI ;get the same access type
CALL DiskOpenHelper ; and reopen the file
; AX = error code if CF
; BX = file handle
JNC DOPEN_PROCESS ;jump if success
; The OPEN failed with the current access. If an access
; failure occurred and the OPEN is allowed to retry using
; another access ([b$ACCESS]=ACCESS_NONE), determine the
; new access and retry the OPEN.
DOPEN_NEXT_ACCESS:
CMP AX,ERRACD ; test if access error
JNE DOPEN_NOT_ACCESS_ERROR ;if not, then branch
CMP [b$ACCESS],ACCESS_NONE ;is a retry possible?
JNE DOPEN_ACCESS_ERROR ;if not, just process error
TEST b$FILMOD,MD_RND+MD_BIN ; test for random or binary modes
JE DOPEN_TRY_APPEND_RETRY ; if not, then jump
OR DI,DI ;is access READ?
JE DOPEN_ACCESS_ERROR ;if so, then jump
MOV BX,DI ;get access code
DEC BX ;r/w->write or write->read
JMP DOPEN_OPEN ;retry random OPEN now
JMP_DOPEN_PROCESS: ; Code is too big and ugly for relative
JMP SHORT DOPEN_PROCESS ; jumps to DOPEN_PROCESS.
DOPEN_TRY_APPEND_RETRY:
CMP b$FILMOD,MD_APP ; test for append mode
JNE DOPEN_ACCESS_ERROR ;jump if not
CMP DI,2 ;test if read/write
JNE DOPEN_ACCESS_ERROR ;jump if not
MOV BX,1 ;make access WRITE
JMP DOPEN_OPEN ;retry append OPEN now
; OPEN failed with error code 5 (carry set). Use extended error
; call (if DOS 3 or later) to determine reported error.
; "PATH/FILE ACCESS ERROR" is reported when failure is due to
; directory restriction. "PERMISSION DENIED" is for DOS 2 or
; OPEN access conflict.
DOPEN_ACCESS_ERROR:
JMP B$OpenErr ; give proper error message, with SI <> FDB.
; (FL_CHAR bit of FD_FLAGS always clear)
; Error not access-related.
DOPEN_NOT_ACCESS_ERROR:
CMP AX,ERRFNF ; error was FILE NOT FOUND?
JE ERCFNF ; brif so
CMP b$FILMOD,MD_SQO ; interpreter compatability
JE ERCTMF ; brif sequential output -- too many files
ERCACD:
JMP B$ERR_ACD
DOPEN_CREATE_ERROR:
CMP AX,ERRACD ; test if access error
JNE DOPEN_NOT_ACCESS_ERROR ; if not, then branch
CALL B$GETEXTERR ; get extended error after creation
JC ERCTMF ; if DOS 2, then give too many files
CMP AX,52H ; test if directory entry creation failed
JNE ERCACD ; if not, then path/access error
ERCTMF:
JMP B$ERR_TMF ; too many files
; OPEN has been completed. Finish details needed for BASCOM.
; BX = file handle
DOPEN_PROCESS:
POP AX ; AX = output from B$GET_PATHNAME
POP DX ; DX = file number
POP CX ; restore buffer size
XCHG DX,BX ; BX = file #, DX = file handle
PUSH DX ; save file handle
; allocate the FDB, and fill some fields
PUSH CX ; save buffer size
ADD CX,PATH_LEN ; add extra space for pathname
MOV DL,255 ; (DL) = width
; fields
MOV AH,255 ; (AH) = all file modes legal
CALL B$DEVOPN ; Allocate file block, set up some fields
FDB_PTR ES,SI,SI ; (ES:)SI = *FDB
POP CX ; get back buffer size
MOV FileDB.FD_VRECL,CX ; set record length/buffer size
LEA DI,FileDB.FD_BUFFER ; ES:DI = address to put pathname in the
ADD DI,CX ; FDB (after I/O buffer)
MOV CX,PATH_LEN ; CX = length of pathname (including null)
PUSH SI ; save FDB address
MOV SI,OFFSET DGROUP:b$PATHNAM ; DS:SI = pathname address
REP MOVSB ; and copy pathname into FDB
POP SI ; SI = FDB address
POP BX ; BX = file handle
MOV FileDB.FD_HANDLE,BX ; save file handle
OR FileDB.FD_FLAGS,FL_NEOF ;set flag for no EOF
mov al,0
callos ioctl ;discover whether character device
mov al,dl
test al,fl_char ;Is it a device?
jz nochar ;Brif not a character device
AND AL,FL_CHAR+FL_CONOUT+FL_CONINP ; Clean all bits except
; FL_CHAR, FL_CONINP, and FL_CONOUT
OR FileDB.FD_FLAGS,AL ;update FDB flags
mov al,1
or dx,32 ; set raw - preserve bits
mov dh,0 ; Must set high byte to zero !
CALLOS IOCTL,ERCIOE ; set raw mode -- I/O error upon failure
;Don't make CON out RAW if DOS 2.+
TEST b$FILMOD,MD_RND+MD_BIN ; random or binary char device?
JNZ NOCHAR ; brif so -- these files have a buffer size
MOV FileDB.FD_VRECL,1 ;yes, set block size to one
CMP b$FILMOD,MD_APP ; if append, convert to MD_SQO
jne nochar
MOV b$FILMOD,MD_SQO
nochar:
MOV AL,b$FILMOD
mov FileDB.FD_MODE,al ;set mode
TEST FileDB.FD_FLAGS,FL_CHAR ; char device?
JNZ NoTruncate ; brif so -- don't truncate file
TEST AL,MD_SQO ; output?
JZ NoTruncate ; brif not -- don't truncate file
OR FileDB.FD_FLAGS,FL_TRUNC ; truncate file upon first write
NoTruncate:
cmp al,MD_APP ; is it append?
JNE OpenExit ; brif not -- exit
cCall B$FILESIZE ; seek to end of file [DX|AX] = file size/pos
MOV CX,AX ; [DX|CX] = file size
OR AX,DX ; empty file?
JZ EmptyApp ; brif so -- don't seek back
; An empty file opened by BASCOM10 has a 1A (^Z) at the begining of
; a block of 128 characters which constitutes the file. Before this
; change the SEEK routine ]was seeking to one past the end of 128
; characters thereby retaining a ^Z at the beginning. The new
; algorithm first seeks to the LAST BLOCK of 128 characters and
; then searches for the first available ^Z or end of file as the
; case may be and starts appending from that point.
SUB CX,128 ; get the last block of 128
SBB DX,0 ; characters
JNB appfi1 ;brif file is more than 128 chars
XOR CX,CX ; set postion to zero
XOR DX,DX
appfi1: ; [DX|CX] = new position
CALL B$SeekFromStart ; position file pointer ([DX|AX] = result)
XCHG AX,CX ; [DX|CX] = file position
MOV b$CLOS_FDB,SI ; deallocate FDB and close file if error
CALL B$DISK_SINP ; read a char. Destroys AX.
MOV b$CLOS_FDB,0 ; finished with critical section
JB appfi2 ; brif got a ctrl z
ADD CX,1 ; check the next guy
ADC DX,0
JMP SHORT appfi1 ; loop around
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -