MS-DOS/v2.0/source/XENIX.ASM
2018-09-21 17:53:34 -07:00

907 lines
25 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; xenix file calls for MSDOS
;
INCLUDE DOSSEG.ASM
IFNDEF KANJI
KANJI EQU 0 ;FALSE
ENDIF
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
TITLE XENIX - IO system to mimic UNIX
NAME XENIX
i_need NoSetDir,BYTE
i_need CURDRV,BYTE
i_need IOCALL,BYTE
i_need IOMED,BYTE
i_need IOSCNT,WORD
i_need IOXAD,DWORD
i_need DIRSTART,WORD
i_need ATTRIB,BYTE
i_need THISFCB,DWORD
i_need AuxStack,BYTE
i_need Creating,BYTE
i_need ThisDRV,BYTE
i_need NAME1,BYTE
i_need LastEnt,WORD
i_need ThisDPB,DWORD
i_need EntLast,WORD
i_need CurrentPDB,WORD
i_need sft_addr,DWORD ; pointer to head of table
i_need CURBUF,DWORD ; pointer to current buffer
i_need DMAADD,DWORD ; pointer to current dma address
BREAK <Local data>
CODE ENDS
DATA SEGMENT BYTE PUBLIC 'DATA'
open_name DW ?
DW ?
open_access DB ?
open_jfn DW ? ; accessed as DD
open_jfn_b DW ? ; accessed as DD with above
open_sfn DW ?
open_sfoff DW ? ; accessed as DD
open_sfn_b DW ? ; accessed as DD with above
open_devid DB ?
Cr_read_only DB ?
rename_source DD ?
rename_dest DD ?
DATA ENDS
CODE SEGMENT BYTE PUBLIC 'CODE'
BREAK <Validate_path - check to see if there are meta characters in path>
;
; Input: DS:DX is an ASCIZ path
; Output: Carry set if meta-characters present or path malformed and
; Zero is set if the only problem is that meta-characters
; are present in the last element of the path
procedure Validate_path,near
ASSUME DS:NOTHING,ES:NOTHING
PUSH AX
PUSH CX
PUSH SI
MOV SI,DX
MOV CX,0FFH ;No path seps yet
MOV AX,[SI] ; Get first two bytes
OR AL,AL
JZ validate_malformed ; NUL path
CMP AH,':'
JNZ validate_loop ; OK so far
CMP BYTE PTR [SI+2],0
JZ validate_malformed ; NUL path (just d:)
validate_loop:
LODSB
validate_loop1:
IF KANJI
invoke TESTKANJ
JZ NOTKANJ6
INC SI
JMP validate_loop
NOTKANJ6:
ENDIF
OR AL,AL
JZ validate_end
CMP AL,"?"
JZ validate_error
CMP AL,"*"
JZ validate_error
invoke PathChrCmp
JNZ validate_loop
JCXZ validate_malformed ;If path sep, cannot have meta yet
LODSB ;Look ahead one char
OR AL,AL
JZ validate_checktslsh ;Trailing path sep
invoke PathChrCmp
JNZ validate_loop1 ;Double path sep?
validate_malformed:
INC CX
OR CX,CX ;Reset zero
JMP SHORT validate_set_carry
validate_error:
XOR CX,CX ;Flag metas found
JMP validate_loop
validate_checktslsh:
;A bizarre case, "/" is OK, "d:/" is OK, anything else is an error
SUB SI,DX
CMP SI,2
JZ validate_end ;Two chars, the '/' and the NUL
CMP SI,4
JNZ validate_malformed ;Four chars, "D:/<NUL>"
MOV SI,DX
CMP BYTE PTR [SI+1],':'
JNZ validate_malformed ;Second char must be a ':'
validate_end:
OR CX,CX ;Clears carry
JNZ validate_ok ;No metas found, leave carry clear
validate_set_carry:
STC
validate_ok:
POP SI
POP CX
POP AX
return
validate_path ENDP
BREAK <Access_path - determine if file found>
;
; Input: DS:DX point to a path
; Output: Carry reset - outputs of GetPath
; carry set - AL has error code
;
procedure Access_path,NEAR
ASSUME DS:NOTHING,ES:NOTHING
CALL Validate_path
JC access_no_path
MOV SI,DX
invoke GetPath
retnc
MOV AL,error_file_not_found
OR CL,CL
JNZ access_ret
access_no_path:
MOV AL,error_path_not_found
access_ret:
STC
return
access_path ENDP
BREAK <Find_free_jfn - return a free jfn in users PDB>
;
; system file table data
;
;
; The system file table is two linear tables. The first table is the
; DOS initialization table containing a default number of FCBs. The
; first word in the table is a link to the second table, which
; SYSINIT sets up, the second word is the number of FCBs in the table.
;
;
; find_free_jfn
; input: none
; output: JNC <found>
; ES:DI is pointer to free JFN
; JC <no free jfns>
; ES,DI indeterminate
;
procedure Find_free_jfn,NEAR
ASSUME DS:NOTHING,ES:NOTHING
PUSH AX
PUSH CX
MOV AL,0FFh
MOV ES,[CurrentPDB]
MOV DI,PDB_JFN_Table
MOV CX,FilPerProc
REPNE SCASB
STC
JNZ Find_jfn_ret
DEC DI
CLC
Find_jfn_ret:
POP CX
POP AX
return
Find_free_jfn ENDP
BREAK <find_free_sfn - return a free sfn and sf pointer>
;
; find_free_sfn
; input: none
; output: JNC <found>
; ES:DI is free sf entry
; SI is sfn
; JC <not found>
; ES,DI,SI indeterminate
;
; sft_addr --> (link) count (fcbs)
; links = -1 means end of list
;
procedure Find_free_sfn,NEAR
ASSUME DS:NOTHING,ES:NOTHING
PUSH BX
PUSH CX
LES BX,sft_addr ; head of chain of tables
XOR SI,SI ; count of sfn
; ES:BX points to table... search through table
Find_sfn_in_table:
CMP BX,-1 ; end of chain
JZ Find_no_free_sfns
MOV DI,sft_table ; offset to sf entry
MOV CX,ES:[BX].sft_count ; count of fcbs in table
Find_sfn:
CMP ES:BYTE PTR [BX+DI].sf_ref_count,0h
JZ Find_got_sfn ; ref count is 0 -> free entry
ADD DI,SIZE sf_entry ; look to next entry
INC SI ; bump sfn
LOOP Find_sfn
LES BX,ES:[BX].sft_link ; link to next
JMP SHORT Find_sfn_in_table ; look for more
Find_no_free_sfns:
STC
JMP SHORT find_ret
Find_got_sfn:
ADD DI,BX
CLC
Find_ret:
POP CX
POP BX
RET
Find_free_sfn ENDP
BREAK <$Open - open a file handle>
;
; Assembler usage:
; LDS DX, Name
; MOV AH, Open
; MOV AL, access
; INT int_command
;
; ACCESS Function
; ------ --------
; open_for_read file is opened for reading
; open_for_write file is opened for writing
; open_for_both file is opened for both reading and writing.
;
; Error returns:
; AX = error_invalid_access
; = error_file_not_found
; = error_access_denied
; = error_too_many_open_files
;
procedure $Open,NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV [Cr_read_only],0
Open_create:
CMP AL,open_for_both ; validate access
JBE OPEN_get_jfn
error error_invalid_access
OPEN_get_jfn:
MOV [open_name+2],DS
context DS
MOV open_name,DX
MOV open_access,AL
invoke Find_free_jfn ; scan through user's area
; ES:DI is the jfn entry
JNC OPEN_get_sfn
OPEN_too_many:
error error_too_many_open_files
OPEN_get_sfn:
MOV OPEN_jfn_b,ES
MOV OPEN_jfn,DI
invoke Find_free_sfn ; get a free sft entry
; ES:DI is the SFT entry that's free, SI is the sfn
JC OPEN_too_many
OPEN_file:
MOV OPEN_sfn,SI
MOV OPEN_sfoff,DI
MOV OPEN_sfn_b,ES
;
; open the file
;
PUSH DS
LDS DX,DWORD PTR [open_name]
ASSUME DS:NOTHING
CALL access_path
POP DS
ASSUME DS:DOSGROUP
JNC open_check_access ; carry set -> error
transfer SYS_RET_ERR
open_check_access:
MOV ES,WORD PTR [CURBUF+2] ; get buffer location
MOV open_devid,AH
TEST AH,080h
JNZ open_set_FCB_dev ;is a device
MOV AL,ES:[BX].dir_attr
TEST AL,attr_directory ; can't open directories
JZ open_try_volid
open_bad_access:
error error_access_denied
open_try_volid:
TEST AL,attr_volume_id ; can't open volume ids
JNZ open_bad_access
TEST AL,attr_read_only ; check write on read only
JZ open_set_FCB
CMP [Cr_read_only],0
JNZ open_set_FCB ; ok if creating read only file
CMP open_access, open_for_read
JNZ open_bad_access ; writing on a read only file
JMP SHORT open_set_FCB
open_set_FCB_dev:
PUSH SS
POP ES ;Device opens are DOSGROUP relative
open_set_FCB:
MOV CX,11 ; copy name into FCB...
PUSH SI ; ES:BX is source, must change
MOV SI,BX ; ES:SI is source
MOV DI,open_sfoff ; ??:DI is dest
PUSH DS
PUSH ES
MOV ES,open_sfn_b ; ES:DI is dest
POP DS ; DS:SI is source
ASSUME DS:NOTHING
;
; need to save attribute for the close operation
;
MOV AH,DS:[BX.dir_attr] ; save attribute for close
MOV ES:[DI.sf_attr],AH
ADD DI,sf_fcb+1 ; point to name
IF KANJI
MOVSB
CMP BYTE PTR ES:[DI-1],5
JNZ NOTKTRAN
MOV BYTE PTR ES:[DI-1],0E5H
NOTKTRAN:
DEC CX
ENDIF
REP MOVSB ; move in parsed name
POP DS
ASSUME DS:DOSGROUP
POP SI
LES DI,DWORD PTR [open_sfoff]
ADD DI,sf_fcb ; offset on fcb in sf entry
MOV AH,open_devid
invoke DOOPEN ; let open code fill in blanks
context DS
LES DI,DWORD PTR [open_sfoff]
INC ES:[DI].sf_ref_count ; reference this FCB
MOV AL,open_access ; stash the access
MOV ES:BYTE PTR [DI].sf_mode,AL
XOR AX,AX
MOV ES:WORD PTR [DI.sf_FCB.fcb_RR],AX ; beginning of file
MOV ES:WORD PTR [DI.sf_FCB.fcb_RR+2],AX
INC AX
MOV ES:WORD PTR [DI.sf_FCB.fcb_RECSIZ],AX ; byte io only
LES DI,DWORD PTR [open_jfn]
MOV AX,open_sfn
MOV ES:BYTE PTR [DI],AL ; stash sfn in PDB
SUB DI,PDB_jfn_table ; get jfn for user
MOV AX,DI
transfer SYS_RET_OK
$Open ENDP
BREAK <$UNLINK - delete a file entry>
;
; Assembler usage:
; LDS DX, name
; MOV AH, Unlink
; INT 21h
;
; Error returns:
; AX = error_file_not_found
; = error_access_denied
;
procedure $UNLINK,NEAR
ASSUME DS:NOTHING,ES:NOTHING
CALL access_path
JNC unlink_check_attr
transfer SYS_RET_ERR
unlink_check_attr:
JZ unlink_dir
LDS DI,DWORD PTR [CURBUF] ; get directory entry
TEST DS:[BX.dir_attr],attr_read_only
JZ unlink_doit
unlink_dir:
error error_access_denied
unlink_doit:
MOV BYTE PTR DS:[BX.dir_name],0E5h ; delete dir entry
MOV BYTE PTR DS:[DI.BUFDIRTY],1 ; dirty the buffer
LODSW
MOV BX,AX
AND BX,0FFFh
context DS
JZ unlink_flush
invoke RELEASE
unlink_flush:
MOV AL,BYTE PTR ES:[BP.DPB_drive]
invoke FLUSHBUF
transfer SYS_RET_OK
$UNLINK ENDP
BREAK <$CREAT - creat a new file and open him for input>
;
; Assembler usage:
; LDS DX, name
; MOV AH, Creat
; MOV CX, access
; INT 21h
; ; AX now has the handle
;
; Error returns:
; AX = error_access_denied
; = error_path_not_found
; = error_too_many_open_files
;
procedure $CREAT,NEAR
ASSUME DS:NOTHING,ES:NOTHING
CALL Validate_path
JNC unlink_do_make
error error_path_not_found
unlink_do_make:
PUSH DX
PUSH DS
context DS
MOV WORD PTR [CREATING],0E5FFh
MOV WORD PTR [ThisFCB+2],SS
MOV WORD PTR [ThisFCB],OFFSET DOSGROUP:AUXSTACK-40
MOV SI,DX
MOV AL,CL
AND CL,attr_read_only
MOV [Cr_read_only],CL
POP DS
PUSH DS
ASSUME DS:NOTHING
invoke MakeNode
POP DS
POP DX
OR AL,AL
JZ creat_open
CMP AL,3
JZ creat_open
creat_no_access:
error error_access_denied
creat_open:
MOV AL,open_for_both
JMP Open_create
$CREAT ENDP
BREAK <$DUP - duplicate a jfn>
;
; Assembler usage:
; MOV BX, fh
; MOV AH, Dup
; INT int_command
; AX has the returned handle
; Errors:
; AX = dup_invalid_handle
; = dup_too_many_open_files
procedure $DUP,NEAR
ASSUME DS:NOTHING,ES:NOTHING
context DS
invoke Find_free_jfn
JC dup_no_free_handles
dup_force:
PUSH ES
PUSH DI
invoke Get_sf_from_jfn
POP SI
POP DS
JC dup_bad_handle
; ES:DI is pointer to sf entry
; DS:DI is pointer to jfn
INC ES:[DI].sf_ref_count ; another jfn reference...
MOV AL,[BX].PDB_JFN_table ; get old sfn
MOV [SI],AL ; store in new place
SUB SI,PDB_JFN_table ; get jfn
MOV AX,SI
transfer SYS_RET_OK
dup_no_free_handles:
error error_too_many_open_files
dup_bad_handle:
error error_invalid_handle
$DUP ENDP
BREAK <$DUP2 - force a dup on a particular jfn>
;
; Assembler usage:
; MOV BX, fh
; MOV CX, newfh
; MOV AH, Dup2
; INT int_command
; Error returns:
; AX = error_invalid_handle
;
procedure $DUP2,NEAR
ASSUME DS:NOTHING,ES:NOTHING
XCHG BX,CX ; BX < destination jfn
PUSH BX
PUSH CX
invoke $CLOSE ; close BX
context DS
POP CX
POP BX
invoke Get_jfn_pointer
XCHG BX,CX
JNC dup_force
lseek_bad_handle:
error error_invalid_handle
$DUP2 ENDP
BREAK <$CHMOD - change file attributes>
;
; Assembler usage:
; LDS DX, name
; MOV CX, attributes
; INT 21h
; Error returns:
; AX = error_path_not_found
; AX = error_access_denied
;
procedure $CHMOD,NEAR
ASSUME DS:NOTHING,ES:NOTHING
CMP AL,1
JBE chmod_save
error error_invalid_function
chmod_save:
JB chmod_try_file
MOV BX,CX
AND BX,NOT attr_changeable
JZ chmod_try_file
chmod_bad:
error error_access_denied
chmod_bye:
transfer SYS_RET_ERR
chmod_try_file:
PUSH CX
PUSH AX
CALL access_path
POP DX
POP CX
JC chmod_bye
LES DI,[CURBUF]
context DS
OR DL,DL
JZ chmod_fetch
AND BYTE PTR ES:[BX].dir_attr,NOT attr_changeable
OR BYTE PTR ES:[BX].dir_attr,CL
MOV ES:[DI.BUFDIRTY],1
MOV AL,-1
invoke FlushBuf
transfer SYS_RET_OK
chmod_fetch:
XOR CX,CX
MOV CL,BYTE PTR ES:[BX].dir_attr
invoke Get_user_stack
MOV [SI.user_CX],CX
transfer SYS_RET_OK
$chmod ENDP
BREAK <$CURRENT_DIR - dump the current directory into user space>
;
; Assembler usage:
; LDS SI,area
; MOV DL,drive
; INT 21h
; ; DS:SI is a pointer to 64 byte area that contains drive
; ; current directory.
; Error returns:
; AX = error_invalid_drive
;
procedure $CURRENT_DIR,NEAR
ASSUME DS:NOTHING,ES:NOTHING
PUSH DS
PUSH BX
PUSH SI
invoke $get_DPB
;
; ES:BP points to DPB. DS:SI points to user stack, unless error
;
CMP AL,0FFh
JNZ current_copy
POP AX ; Clean Stack
POP AX
POP AX
error error_invalid_drive
current_copy:
POP DI ; where to move to
POP [SI.user_BX] ; restore old BX
POP BX
MOV [SI.user_DS],BX ; and restore old DS
;
; ES:BP is pointer to DPB. BX:DI is pointer to destination
;
CMP ES:[BP.dpb_current_dir],-1
JNZ current_ok
PUSH BX
PUSH DI
MOV [ATTRIB],attr_all
invoke GETCURRDIR
POP DI
POP BX
current_ok:
MOV SI,BP ; ES:SI is source
PUSH ES
POP DS ; DS:SI is source
MOV ES,BX ; ES:DI is destination
CMP [SI.dpb_current_dir],0
JNZ current_move
MOV BYTE PTR [SI.dpb_dir_text],0
current_move:
ADD SI,dpb_dir_text
MOV CX,DIRSTRLEN
current_loop:
LODSB
STOSB
OR AL,AL
LOOPNZ current_loop
transfer SYS_RET_OK
$CURRENT_DIR ENDP
BREAK <$RENAME - move directory entries around>
;
; Assembler usage:
; LDS DX, source
; LES DI, dest
; MOV AH, Rename
; INT 21h
;
; Error returns:
; AX = error_file_not_found
; = error_not_same_device
; = error_access_denied
procedure $RENAME,near
MOV WORD PTR [rename_source],DX
MOV WORD PTR [rename_source+2],DS
MOV WORD PTR [rename_dest],DI
MOV WORD PTR [rename_dest+2],ES
CALL Access_path
JNC rename_check_dir
transfer SYS_RET_ERR
rename_check_dir:
JZ rename_no_access
MOV DS,WORD PTR [CurBuf+2]
PUSH [BX.dir_date]
PUSH [BX.dir_first]
PUSH [BX.dir_size_h]
PUSH [BX.dir_size_l]
PUSH [BX.dir_time]
PUSH WORD PTR [BX.dir_attr]
PUSH WORD PTR [ThisDrv]
LDS SI,[rename_dest]
invoke GetPath
POP AX
JC rename_check_drives
rename_bad_access:
ADD SP,12
rename_no_access:
error error_access_denied
rename_check_drives:
CMP AL,[ThisDrv]
JZ rename_create
ADD SP,12
error error_not_same_device
rename_create:
LDS SI,[rename_dest]
POP AX
PUSH AX
MOV WORD PTR [Creating],0E5FFh
MOV WORD PTR [ThisFCB+2],SS
MOV WORD PTR [ThisFCB],OFFSET DOSGROUP:AUXStack-40
invoke MakeNode
JC rename_bad_access
LDS SI,[CurBuf]
POP AX
MOV [BX.dir_attr],AL
POP [BX.dir_time]
POP [BX.dir_size_l]
POP [BX.dir_size_h]
POP [BX.dir_first]
POP [BX.dir_date]
MOV [SI.BUFDIRTY],1
LDS SI,[rename_source]
invoke GetPath
LDS SI,[CurBuf]
MOV BYTE PTR [BX],0E5h
MOV [SI.BUFDIRTY],1
context DS
MOV AL,0FFh
invoke FlushBuf
transfer SYS_RET_OK
$RENAME ENDP
BREAK <$FIND_FIRST - find first matching xenix filename>
;
; Assembler usage:
; MOV AH, FindFirst
; LDS DX, name
; MOV CX, attr
; INT 21h
; ; DMA address has datablock
;
; Error Returns:
; AX = error_file_not_found
; = error_no_more_files
;
procedure $FIND_FIRST,near
ASSUME DS:NOTHING,ES:NOTHING
CALL Validate_path
JNC find_get
JZ find_get
error error_file_not_found
find_get:
MOV SI,DX
PUSH CX
INC BYTE PTR [NoSetDir] ; if we find a dir, don't change to it
MOV WORD PTR [Creating],0E500h
CALL GetPath
POP CX
MOV [Attrib],CL
find_check:
JNC find_check_attr
find_no_more:
error error_no_more_files
find_check_attr:
MOV DS,WORD PTR [CURBUF+2]
MOV CH,[BX.dir_attr]
invoke MatchAttributes
JZ found_it
PUSH [LastEnt]
MOV BX,[DirStart]
JMP find_it_next
found_it:
LES DI,[DMAADD]
MOV AL,[Attrib]
STOSB ; find_buf 0 = attribute in search
MOV AL,[ThisDrv]
STOSB ; find_buf 1 = drive
MOV CX,11
PUSH BX
MOV SI,OFFSET DOSGROUP:NAME1; find_buf 2 = formatted name
PUSH DS
PUSH SS
POP DS
IF KANJI
MOVSB
CMP BYTE PTR ES:[DI-1],5
JNZ NOTKANJB
MOV BYTE PTR ES:[DI-1],0E5H
NOTKANJB:
DEC CX
ENDIF
REP MOVSB
POP DS
MOV AX,[LastEnt]
STOSW ; find_buf 13 = LastEnt
MOV AX,WORD PTR [ThisDPB]
STOSW ; find_buf 15 = ThisDPB
MOV AX,WORD PTR [ThisDPB+2]
STOSW
MOV AX,[DirStart]
STOSW ; find_buf 19 = DirStart
MOV AL,[BX].dir_attr
STOSB ; find_buf 21 = attribute found
MOV AX,[BX].dir_time
STOSW ; find_buf 22 = time
MOV AX,[BX].dir_date
STOSW ; find_buf 24 = date
MOV AX,[BX].dir_size_l
STOSW ; find_buf 26 = low(size)
MOV AX,[BX].dir_size_h
STOSW ; find_buf 28 = high(size)
POP SI
MOV CX,8 ; find_buf 30 = packed name
find_loop_name:
LODSB
STOSB
CMP AL," "
LOOPNZ find_loop_name
JNZ find_check_dot
DEC DI
find_check_dot:
ADD SI,CX
CMP BYTE PTR [SI]," "
JZ find_done
MOV AL,"."
STOSB
MOV CX,3
find_loop_ext:
LODSB
STOSB
CMP AL," "
LOOPNZ find_loop_ext
JNZ find_done
DEC DI
find_done:
XOR AL,AL
STOSB
transfer SYS_RET_OK
$FIND_FIRST ENDP
BREAK <$FIND_NEXT - scan for match in directory>
;
; Assembler usage:
; ; dma points at area returned by find_first
; MOV AH, findnext
; INT 21h
; ; next entry is at dma
;
; Error Returns:
; AX = error_no_more_files
;
procedure $FIND_NEXT,near
ASSUME DS:NOTHING,ES:NOTHING
LDS SI,[DMAADD]
MOV DX,SI
INC DX
PUSH SI
invoke MOVNAMENOSET
POP SI
JNC find_load
findnext_no_more:
error error_no_more_files
find_load:
MOV AX,[SI.find_buf_LastEnt]
LES BP,[SI.find_buf_ThisDPB]
OR AX,AX
JS findnext_no_more
MOV BX,[SI.find_buf_DirStart]
MOV DL,[SI.find_buf_sattr]
MOV [Attrib],DL
PUSH AX
MOV WORD PTR [ThisDPB],BP
MOV WORD PTR [ThisDPB+2],ES
find_it_next:
invoke SetDirSrch
ASSUME DS:DOSGROUP
POP AX
MOV [ENTLAST],-1
invoke GetEnt
invoke NextEnt
JMP find_check
$find_next ENDP
do_ext
CODE ENDS
END