Files
DR-DOS-OpenDOS/COMMAND/DOSIF.ASM
2020-11-04 23:59:28 +01:00

2908 lines
58 KiB
NASM

; File : $Workfile: DOSIF.ASM$
;
; Description :
;
; Original Author :
;
; Last Edited By : $Author: RGROSS$
;
; Copyright : (C) 1992 Digital Research (UK), Ltd.
; Charnham Park
; Hungerford, Berks.
; U.K.
;
; *** Current Edit History ***
; *** End of Current Edit History ***
;
; $Log: $
; DOSIF.ASM 1.1 94/06/28 16:01:14 RGROSS
; Initial PUT
; DOSIF.ASM 1.16 94/06/28 16:01:28 IJACK
; ms_x_expand returns error codes (for benefit of TRUENAME)
; DOSIF.ASM 1.15 93/11/29 19:57:24 IJACK
;
; --------
;
; DOSIF.ASM 1.13 93/09/09 10:24:50 RFREEBOR
; call_novell() now returns all allowed error codes.
;
; DOSIF.ASM 1.12 93/02/24 17:42:49 EHILL
; _get_scr_width() function added.
;
; DOSIF.ASM 1.11 93/01/21 16:19:31 EHILL
;
; DOSIF.ASM 1.10 93/01/21 14:32:32 EHILL
;
; DOSIF.ASM 1.8 92/09/11 10:46:28 EHILL
;
; DOSIF.ASM 1.7 92/08/06 09:56:07 EHILL
; Added DOS 5 calls to get and set memory allocation strategy and
; upper memory link.
;
; DOSIF.ASM 1.6 92/07/10 17:47:13 EHILL
; No comment
;
; ENDLOG
;
; This file provides all the assembler level interfaces to the
; underlying operating system that are required by COMMAND.COM.
; The type of functions calls that will be made is controlled
; by a Assemble time flag.
;
; Currently the Operating System Interfaces that are supported
; are MS-DOS and Concurrent DOS 6.0.
;
;
; Command Line Flags
; ==================
;
; MSDOS If defined then USE MSDOS function Calls
; CDOS If defined then Use Concurrent DOS Calls
;
;
; 2/Sep/87 jc Convert the Concurrent IOCTL function to use the FDOS
; command.
; 19/Oct/87 jc Handle Fail on Get current directory correctly
; 23/Feb/88 jc Use Text substitution function to get the path assigned
; to floating drives (ms_x_subst).
; 3/Mar/88 jc Support Server Password Error
; 9/Mar/88 jc Return a NULL terminated string when an error occurs on the
; ms_x_subst function.
; 15/Mar/88 jc Correct ms_x_subst register corruption bug
; 13/Apr/88 jc Support the FAR_READ and FAR_WRITE routines as well as external
; copy buffer allocation via MEM_ALLOC and MEM_FREE
; 20/May/88 jc Return the current country code to the calling application
; 25/May/88 jc Missing dataOFFSET causing garbage offset to be passed
; ms_x_subst.
; 18/Jul/88 jc Modify LOGICAL_DRV test to detect substituted physical drives
; 17/Aug/88 jc Return the current Break Status using DL not AL
; 22/Sep/88 jc Replace MS_X_SUBST with more general MS_X_EXPAND routine
; 25/Jan/89 ij If new DRDOS internal data layout get DPHTBL the new way
; 07/Feb/89 jc Add the Get and Set Global Codepage MS_X_GETCP/MS_X_SETCP
; 25/Jan/89 ij Get DPHTBL using DRDOS_DPHTBL_OFFSET equate
; 14/Apr/89 jjs Add ms_x_setdev
; 31/May/89 ij Get SYSDAT for DPHTBL using new f4458 function
; 19/May/89 jc Remove "Alternative" techniques of getting SYSDAT:DPHTABLE
; 20/Jun/89 js ms_f_parse, ms_f_delete, for DEL cmd
; 30/Aug/89 js ms_idle_ptr
; 6/Sep/89 ij network_drvs really does something on DRDOS
; 16/Oct/89 ach Added double byte character set support routines: dbcs_init,
; dbcs_expected and dbcs_lead.
; 18/Jan/90 ij HILOAD interfaces added
; 4/Apr/90 ij dbcs_init moved to cstart, use system table, then we can throw
; away the init code
; 24-May-90 ij ms_x_expand sets up ES....
; 17 Sep 90 ij TMP Control Break kludge echo's ^C to console
; 4 Oct 90 ij Use P_CAT, not P_HDS
; 15 Mar 91 jc DRDOS_DPHTBL is now called SYSDAT_DPHTBL cos thats where it lives
; 28 May 91 ejh No longer use SYSDAT to determine if drives are physical,
; logical or networked. See _physical_drive, _logical_drive and
; _network_drive.
; 23 Jun 91 ejh SUBST and ASSIGN are now external commands, so the following
; are no longer required:
; _physical_drvs, _logical_drvs, _network_drvs
; _physical_drive,_logical_drive,_network_drive
; 3 jul 91 ij except for NETDRIVE in MDOS
;
; 18 Jun 92 ejh Added get_lines_page() function.
; 24 Jun 92 ejh Added novell_copy() function.
CGROUP group _TEXT
DGROUP group _DATA
codeOFFSET equ offset CGROUP:
dataOFFSET equ offset DGROUP:
EXT_SUBST equ 1 ; External Subst and Assign commands
CRET MACRO num
ret
ENDM
ifndef ??Version ;; Turbo Assembler always knows RETF
ifndef retf ;; some versions of MASM do as well
retf macro ;; define far return macro for others
db 0cbh
endm
endif
endif
ifndef CDOSTMP
include msdos.equ
endif
ifndef DOSPLUS
include system.def
include pd.def
include ccpm.equ
;include udaa.def
include net.def
include mserror.equ
else
include f52data.def
endif
;
ifdef CDOSTMP
OK_RIF equ 00111000b ; All Responsese are Valid
OK_RI equ 00110000b ; Retry and Ignore are Valid
OK_RF equ 00011000b ; Retry and Fail are Valid
;
; Structure of DOS DPB
; --------------------
; The layout of this structure is a guess based on
; examples. It is returned by PC MODE on functions 1Fh and
; 32h and is required by various disk-related utilities
; like disk editors and CHKDSK.
DDSC_UNIT equ es:byte ptr 0 ; absolute drive number
DDSC_RUNIT equ es:byte ptr 1 ; relative unit number
DDSC_SECSIZE equ es:word ptr 2 ; sector size in bytes
DDSC_CLMSK equ es:byte ptr 4 ; sectors/cluster - 1
DDSC_CLSHF equ es:byte ptr 5 ; log2 (sectors/cluster)
DDSC_FATADDR equ es:word ptr 6 ; sector address of FAT
DDSC_NFATS equ es:byte ptr 8 ; # of FAT copies
DDSC_DIRENT equ es:word ptr 9 ; size of root directory
DDSC_DATADDR equ es:word ptr 11 ; sector address of cluster #2
DDSC_NCLSTRS equ es:word ptr 13 ; # of clusters on disk
DDSC_NFATRECS equ es:byte ptr 15 ; # of sectors per FAT
DDSC_DIRADDR equ es:word ptr 16 ; sector address of root dir
DDSC_DEVHEAD equ es:dword ptr 18 ; device driver header
DDSC_MEDIA equ es:byte ptr 22 ; current media byte
DDSC_FIRST equ es:byte ptr 23 ; "drive never accessed" flag
DDSC_LINK equ es:dword ptr 24 ; next drive's DDSC
DDSC_BLOCK equ es:word ptr 28 ; next block to allocate
DDSC_FREE equ es:word ptr 30 ; total free clusters on drive
DDSC_MAP equ es:word ptr 32 ; free blocks/FAT sector
endif
BDOS_INT equ 224 ; ##jc##
_DATA SEGMENT byte public 'DATA'
extrn __psp:word
ifndef DOSPLUS
extrn _pd:dword ; Process Descriptor Pointer
endif
extrn _country:WORD
ifdef DOSPLUS
extrn dbcs_table_ptr:dword ; points to system DBCS table
endif
ifdef CDOSTMP
;
; The following buffer is used by the P_PATH function.
; FINDFILE uses the first three fields to get the full path and
; filename of the command.
;
exec_block label byte
exec_pathoff dw ? ; Offset of ASCIIZ Load file
exec_pathseg dw ? ; Segment of ASCIIZ Load File
exec_filetype db ? ; File Type Index
fdos_data dw 7 dup(0) ; FDOS parameter Block
mpb_start dw ? ; Memory parameter Block
mpb_min dw ?
mpb_max dw ?
mpb_pdadr dw ?
mpb_flags dw ?
mfpb_start dw ? ; Memory Free Parameter Block
mfpb_res dw ?
country_data label word ; GET country data
cd_country dw ? ; Requested Country Code
cd_codepage dw ? ; Requested Code Page
cd_table dw ? ; Table Number
cd_offset dw ? ; Buffer Offset
cd_segment dw ? ; Buffer Segment
valid dw 0 ; Valid Error Responses
retry_ip dw 0 ; Critical Error Retry IP
retry_sp dw 0 ; Critical Error Retry SP
crit_flg db FALSE ; Critical Section of Error Handler
include fdos.def
endif
ifdef NETWARE
ipx label dword
ipx_offset dw 0
ipx_segment dw 0
;
; Socket Allocation by Novell
;
; Socket Nos 4000 and 4001 appear to be used by the IPX internally
; and these are NOT closed by the NET_WARE routine. All other USER
; sockets are closed.
;
; List of sockets to be closed on shutdown
; Start Count
socket label word
;; dw 0001h, 0BB8h
dw 4002h, 3FFFh - 2 ; User Socket Numbers
dw 0, 0
aes label byte ; Event Control Block
aes_link label dword ; Link Field
aes_linkoff dw 0
aes_linkseg dw 0
aes_esr label dword ; Service Routine Address
aes_esroff dw codeOFFSET aes_retf
aes_esrseg dw 0000
aes_inuse db 0 ; Flag Field
aes_workspc db 5 dup(?) ; AES WorkSpace
endif
_DATA ENDS
_TEXT SEGMENT byte public 'CODE'
assume cs:CGROUP, ds:DGROUP, es:DGROUP
extrn _int_break:near ; Control-C Break Handler
ifdef CDOSTMP
ifdef MWC
extrn _critical_error:near ; Default Critical Error Handler
CRITICAL_ERR equ _critical_error
else
extrn CRITICAL_ERROR:near ; Default Critical Error Handler
CRITICAL_ERR equ CRITICAL_ERROR
endif
endif
;
; UWORD psp_poke(WORD handle, BYTE ifn);
;
Public _psp_poke
_psp_poke:
push bp
mov bp,sp
push es
ifdef CDOSTMP
mov es,__psp ; ES:0 -> our PSP
else
mov ah,MS_P_GETPSP
int DOS_INT ; for software carousel
mov es,bx
endif
les bx,es:[0034h] ; ES:BX -> external file table
add bx,4[bp] ; ES:BX -> XFT entry for our handle
mov al,6[bp] ; get new value to use
xchg al,es:[bx] ; get old value, set new value
xor ah,ah
pop es
pop bp
ret
ifndef CDOSTMP
Public _ms_drv_set
;-----------
_ms_drv_set:
;-----------
push bp
mov bp,sp
mov dl,04[bp]
mov ah,MS_DRV_SET ; Select the Specified Disk Drive
int DOS_INT ; Nothing Returned to caller
pop bp
ret
Public _ms_drv_get
;-----------
_ms_drv_get:
;-----------
mov ah,MS_DRV_GET ; Return the Currently selected
int DOS_INT ; disk drive
cbw
ret
Public _ms_drv_space
;------------
_ms_drv_space:
;------------
;
; ret = _ms_drv_space (drive, &free, &secsiz, &nclust);
; where: drive = 0, 1-16 is drive to use
; free = free cluster count
; secsiz = bytes/sector
; nclust = clusters/disk
; ret = sectors/cluster -or- (0xFFFFh)
push bp
mov bp,sp
mov dx,4[bp]
mov ah,MS_DRV_SPACE
int DOS_INT
push bx
mov bx,6[bp] ; get free cluster count
pop word ptr [bx]
mov bx,8[bp]
mov [bx],cx ; bytes/sector
mov bx,10[bp]
mov [bx],dx ; clusters/disk
cbw
pop bp
ret
Public _ms_s_country
;------------
_ms_s_country:
;------------
push bp
mov bp,sp
mov ax,MS_S_COUNTRY shl 8 ; Get the curremt country information
mov dx,4[bp] ; and return the current country code
int DOS_INT ; to the calling application.
mov ax,bx
pop bp
ret
Public _ms_x_mkdir
;----------
_ms_x_mkdir:
;----------
mov ah,MS_X_MKDIR
jmp ms_dx_call
Public _ms_x_rmdir
;----------
_ms_x_rmdir:
;----------
mov ah,MS_X_RMDIR
jmp ms_dx_call
Public _ms_x_chdir
;----------
_ms_x_chdir:
;----------
mov ah,MS_X_CHDIR
jmp ms_dx_call
Public _ms_x_creat
;----------
_ms_x_creat:
;----------
mov ah,MS_X_CREAT
jmp ms_open_creat
Public _ms_x_open
;---------
_ms_x_open:
;---------
mov ah,MS_X_OPEN
ms_open_creat:
push bp
mov bp,sp
mov dx,4[bp]
mov cx,6[bp] ; get mode for new file (CREAT)
mov al,cl ; or open mode (OPEN)
int DOS_INT
jnc ms_open_ret ; AX = handle if no error
neg ax ; else mark as error code
ms_open_ret:
pop bp
ret
Public _ms_x_close
;----------
_ms_x_close:
;----------
push bp
mov bp,sp
mov bx,4[bp] ; get the open handle
mov ah,MS_X_CLOSE ; get the function
jmp ms_call_dos ; call DOS, handle errors
Public _ms_x_unique
;----------
_ms_x_unique:
;----------
mov ah,MS_X_MKTEMP
jmp ms_open_creat
Public _ms_x_fdup
;----------
_ms_x_fdup:
;----------
push bp
mov bp,sp
mov cx,4[bp] ; get the destination handle
mov bx,6[bp] ; Get the current handle
mov ah,MS_X_DUP2 ; get the function
jmp ms_call_dos ; call DOS, handle errors
Public _far_read
;---------
_far_read:
;---------
mov ah,MS_X_READ
jmp far_read_write
Public _far_write
;----------
_far_write:
;----------
mov ah,MS_X_WRITE
far_read_write:
push bp
mov bp,sp
push ds
mov bx,4[bp] ; get file handle
lds dx,dword ptr 6[bp] ; get buffer address
mov cx,10[bp] ; get byte count
int DOS_INT ; call the DOS
jnc far_rw_ok ; skip if no error
neg ax ; else make it negative error code
far_rw_ok:
pop ds
pop bp
ret
Public _ms_x_read
;---------
_ms_x_read:
;---------
mov ah,MS_X_READ
jmp ms_read_write
Public _ms_x_write
;----------
_ms_x_write:
;----------
mov ah,MS_X_WRITE
ms_read_write:
push bp
mov bp,sp
mov bx,4[bp] ; get file handle
mov dx,6[bp] ; get buffer address
mov cx,8[bp] ; get byte count
int DOS_INT ; call the DOS
jnc ms_rw_ok ; skip if no error
neg ax ; else make it negative error code
ms_rw_ok:
pop bp
ret
Public _ms_x_unlink
;-----------
_ms_x_unlink:
;-----------
mov ah,MS_X_UNLINK
jmp ms_dx_call
Public _ms_x_lseek
;----------
_ms_x_lseek:
;----------
push bp
mov bp,sp
mov ah,MS_X_LSEEK ; get the function
mov bx,4[bp] ; get the file handle
mov dx,6[bp] ; get the offset
mov cx,8[bp]
mov al,10[bp] ; get the seek mode
int DOS_INT
jnc ms_lseek_ok ; skip if no errors
neg ax ; make error code negative
cwd ; sign extend to long
ms_lseek_ok:
mov bx,dx ; AX:BX = DRC long return
pop bp
ret
Public _ms_x_ioctl
;----------
_ms_x_ioctl:
;----------
push bp
mov bp,sp
mov bx,4[bp] ; get our handle
mov ah,MS_X_IOCTL ; get IO Control function
mov al,0 ; get file/device status
int DOS_INT ; do INT 21h
jnc ms_x_i10
neg ax
ms_x_i10:
pop bp ;
ret
Public _ms_x_setdev
;------------
_ms_x_setdev:
;------------
push bp
mov bp, sp
mov bx, 4[bp] ; handle
mov dx, 6[bp] ; byte value to set
sub dh, dh
mov ah, MS_X_IOCTL
mov al, 1
int DOS_INT
jnc ms_x_sd10
neg ax
ms_x_sd10:
pop bp
ret
Public _ms_x_chmod
;----------
_ms_x_chmod:
;----------
push bp
mov bp,sp
mov ah,MS_X_CHMOD
mov dx,4[bp]
mov cx,6[bp]
mov al,8[bp]
int DOS_INT
jnc ms_chmod_ok
neg ax ; make error code negative
jmp ms_chmod_ret
ms_chmod_ok:
sub ax,ax ; assume no error
cmp byte ptr 8[bp],0 ; getting attributes
jne ms_chmod_ret ; return ax = 0 if setting & no error
xchg ax,cx ; return ax = attrib otherwise
ms_chmod_ret:
pop bp
ret
Public _ms_x_curdir
;-----------
_ms_x_curdir:
;-----------
push bp
mov bp,sp
push si
mov si,6[bp] ; Get the buffer address and
mov byte ptr [si],0 ; put a zero in the first byte in
mov ah,MS_X_CURDIR ; the command is FAILED
push word ptr 4[bp]
call ms_dx_call
pop dx
pop si
pop bp
ret
Public _ms_x_exit
;---------
_ms_x_exit:
;---------
push bp
mov bp,sp
ifdef NETWARE
push es ; If this is Novell Netware and
mov ax,__psp ; the command processor is terminating
mov es,ax ; ie PSP_PARENT == PSP then do the
cmp ax,es:word ptr 16h ; special Novell Close down sequence
pop es
jnz ms_x_exit10
mov ax,7A00h ; Check for IPX being present using
int 2Fh ; the Multi-Plex Interrupt.
cmp al,0FFh
jz net_ware
ms_x_exit10:
endif
mov al,04[bp] ; Get the Return Code
mov ah,MS_X_EXIT ; terminate process function
int DOS_INT ; call the DOS
pop bp
ret
ifdef NETWARE
;
; The following routine attempts to clean-up after a Novell
; session. It does so in the following manner:-
;
; 1) Close all file handles (May be Networked !!)
; 2) Close all User Sockets
; 3) Remove all User Events from Internal lists
; 4) Use CDOS terminate function
;
net_ware:
mov ipx_offset,di
mov ipx_segment,es
mov cx,20 ; Close all the possible handles
mov bx,0 ; used by the command processor
net_w05: ; in case any have been redirected
mov ah,MS_X_CLOSE ; accross the Network
int DOS_INT
inc bx
loop net_w05
mov si,dataOFFSET socket
net_w10:
mov cx,word ptr 02[si] ; Get the number of sockets to close
mov dx,word ptr 00[si] ; starting at Socket No.
jcxz net_w30 ; Terminate on a 0 Count
push si
net_w20:
push cx
push dx ; Save Count and Socket No.
xchg dl,dh ; Swap socket no to High/Low
mov bx,1 ; Close Socket Function
call ipx ; Close Socket.
pop dx
pop cx
inc dx ; Increment Socket No
loop net_w20 ; and Loop
pop si
add si,4 ; Point to next entry in the array
jmp net_w10 ; and repeat till count is 0
net_w30: ; All sockets have been closed
mov aes_esrseg,cs
mov ax,0FFFFh ; Create Special event with the
mov bx,7 ; maximum time delay
push ds
pop es ; Pass the address of the Special
mov si,dataOFFSET aes ; Event control block call the IPX
call ipx
net_w40:
les si,aes_link ; Remove all entries from the Link
; Which are not owned by the IPX
net_w50:
mov bx,es ; get the AES segment
cmp bx,ipx_segment ; and check for a match
jnz net_w60 ; Remove this entry
les si,es:dword ptr [si] ; get the next entry and try again
jmp short net_w50
net_w60:
or bx,si ; End of List
jz net_w70 ; Yes terminate our entry
mov bx,0006h ; Cancel this event
call ipx
jmp short net_w40
net_w70:
mov bx,0006h ; Cancel our event
push ds
pop es
mov si,dataOFFSET aes
call ipx
net_exit:
mov dh,0 ; Standard Exit
mov dl,04[bp] ; With the supplied ExitCode
mov cx,P_EXITCODE ; Set the ExitCode for the Parent
int BDOS_INT
mov cx,P_TERMCPM ; Use a Concurrent Terminate Call
int BDOS_INT ; because Novell has taken over 4Ch
aes_retf: ; Dummy AES routine
retf
endif
;
; ms_x_expand(dstbuf, srcbuf) returns the full path of SRCBUF
;
Public _ms_x_expand
;-----------
_ms_x_expand:
;-----------
push bp
mov bp,sp
push si
push di
mov si,06[bp] ; Get the source String Address
mov di,04[bp] ; Get the destination string
mov byte ptr [di],0 ; address and force it to be a NULL
push ds
pop es ; ES:DI -> destination
mov ah,60h ; terminated string in case of errors
int DOS_INT
jc ms_exp_ret ; skip if error
xor ax,ax ; signal no errors
ms_exp_ret:
neg ax ; make error negative, 0 = 0
pop di
pop si
pop bp
CRET 4
Public _ms_x_wait
;---------
_ms_x_wait: ; retrieve child return code
;---------
mov ah,MS_X_WAIT ; Top byte is abort code ie ^C
int DOS_INT ; Bottom byte is return code
ret
Public _ms_x_first
;----------
_ms_x_first:
;----------
push bp
mov bp,sp
mov dx,8[bp] ; get DMA buffer address
mov ah,MS_F_DMAOFF
int DOS_INT
mov dx,4[bp] ; get ASCII string
mov cx,6[bp] ; get attribute
mov ah,MS_X_FIRST ; get search function
jmp ms_call_dos ; call DOS, check for errors
Public _ms_x_next
;---------
_ms_x_next:
;---------
push bp
mov bp,sp
mov dx,4[bp] ; get DMA buffer address
mov ah,MS_F_DMAOFF
int DOS_INT
mov ah,MS_X_NEXT ; get the function
jmp ms_call_dos ; get DX, call DOS, handle errors
ms_dx_call: ; call DOS with parameter in DX
push bp
mov bp,sp
mov dx,4[bp]
ms_call_dos:
int DOS_INT
jnc ms_dos_ok ; no carry = no error
neg ax ; else make it negative
jmp ms_dos_ret ; and return with error
ms_dos_ok:
sub ax,ax ; return 0 if no error
ms_dos_ret:
pop bp ; return 0 or negative error code
ret
Public _ms_x_rename
;-----------
_ms_x_rename:
;-----------
push bp
mov bp,sp
push di
push ds
pop es
mov ah,MS_X_RENAME
mov di,6[bp] ; ES:DI = new name
push word ptr 4[bp] ; make it look like DRC call
call ms_dx_call ; DX = 4[bp], call DOS, handle errors
pop di ; remove parameter
pop di
pop bp
ret
Public _ms_x_datetime
; ret = _ms_x_datetime (gsflag, h, &time, &date);
;-------------
_ms_x_datetime:
;-------------
push bp
mov bp,sp
mov ah,MS_X_DATETIME ; set/get time stamp function
mov al,4[bp] ; get/set subfunction (0/1)
mov bx,8[bp] ; get address of time
mov cx,[bx] ; get time
mov bx,10[bp] ; get address of date
mov dx,[bx] ; get date
mov bx,6[bp] ; get handle
int DOS_INT ; call the DOS
jc ms_dt_ret ; skip if error
sub ax,ax ; signal no errors
cmp byte ptr 4[bp],0 ; geting time/date?
jne ms_dt_ret ; skip if setting
mov bx,8[bp] ; get time address
mov [bx],cx ; update time
mov bx,10[bp] ; get date address
mov [bx],dx ; update date
ms_dt_ret:
neg ax ; make error negative, 0 = 0
pop bp
ret
;
; The following routines allow COMMAND.COM to manipulate
; the system time and date. Four functions are provided and
; these are MS_GETDATE, MS_SETDATE, MS_GETTIME and MS_SETTIME
;
; Date information is passed and return in a structure which
; has the following format.
;
; WORD Year (1980 - 2099)
; BYTE Month
; BYTE Day
; BYTE Day of the Week (Ignored on SET DATE)
Public _ms_getdate
_ms_getdate:
push bp
mov bp,sp
mov ah,MS_T_GETDATE ; get the current date from DOS
int DOS_INT
mov bx,4[bp] ; and get the structure address
mov [bx],cx ; save the year
xchg dh,dl ; swap month and day
mov 2[bx],dx ; and save
mov 4[bx],al ; and finally save the day number
pop bp ; and exit
ret
Public _ms_setdate
_ms_setdate:
push bp
mov bp,sp
mov bx,4[bp] ; and get the structure address
mov cx,0[bx] ; det the year
mov dx,2[bx] ; get the month and day
xchg dh,dl ; swap month and day
mov ah,MS_T_SETDATE ; set the current date
int DOS_INT
cbw ; 0000 = Ok and FFFF = Bad
pop bp ; and exit
ret
; Time information is passed and return in a structure which
; has the following format.
;
; BYTE Hours (0 - 23)
; BYTE Minutes (0 - 59)
; BYTE Seconds (0 - 59)
; BYTE Hundredths of a second (0 - 99)
Public _ms_gettime
_ms_gettime:
push bp
mov bp,sp
mov ah,MS_T_GETTIME ; get the current date from DOS
int DOS_INT
mov bx,4[bp] ; and get the structure address
xchg cl,ch
mov [bx],cx ; save the hours and minutes
xchg dh,dl
mov 2[bx],dx ; save seconds and hundredths
pop bp ; and exit
ret
Public _ms_settime
_ms_settime:
push bp
mov bp,sp
mov bx,4[bp] ; and get the structure address
mov cx,[bx] ; get the hours and minutes
xchg cl,ch
mov dx,2[bx] ; get seconds and hundredths
xchg dh,dl
mov ah,MS_T_SETTIME ; get the current date from DOS
int DOS_INT
cbw ; 0000 = Ok and FFFF = Bad
pop bp ; and exit
ret
Public _ms_idle_ptr
;------------
_ms_idle_ptr:
;------------
push es
push si
push di
mov ax, 4458h
int DOS_INT ; ptr in ES:AX
mov dx, es
pop di
pop si
pop es
ret
Public _ms_switchar
;-----------
_ms_switchar:
;-----------
mov ax,3700h
int DOS_INT
sub ah,ah
mov al,dl
ret
if 0
Public _ms_p_getpsp
;-----------
_ms_p_getpsp:
;-----------
mov ah,51h ; Note: SeCRET DOS 2.x entry
int DOS_INT
xchg ax,bx
ret
endif
Public _ms_f_verify
;-----------
_ms_f_verify:
;-----------
push bp
mov bp,sp
mov ah,MS_F_VERIFY
mov al,4[bp] ;get 0/1 al parameter
int DOS_INT
pop bp
ret
Public _ms_f_getverify
;--------------
_ms_f_getverify:
;--------------
mov ah,MS_F_GETVERIFY
int DOS_INT
cbw
ret
ifndef CDOSTMP
Public _ms_f_parse
;-----------
_ms_f_parse:
;-----------
push bp
mov bp, sp
push es
push si
push di
push ds
pop es
mov di, 4[bp] ; fcb
mov si, 6[bp] ; filename
mov al, 8[bp] ; flags
mov ah, MS_F_PARSE
int DOS_INT
cbw ; return code in ax
pop di
pop si
pop es
pop bp
ret
Public _ms_f_delete
;------------
_ms_f_delete:
;------------
push bp
mov bp, sp
mov dx, 4[bp] ; fcb
mov ah, MS_F_DELETE
int DOS_INT
cbw ; return code
pop bp
ret
endif
;
; The SET BREAK function returns the previous Break Flag Status
;
Public _ms_set_break
;------------
_ms_set_break:
;------------
push bp
mov bp,sp
mov dl,04[bp]
mov ax,(MS_S_BREAK SHL 8) + 2
int DOS_INT
pop bp
mov al,dl
cbw
ret
if 0
Public _ms_get_break
;------------
_ms_get_break:
;------------
mov ax,MS_S_BREAK SHL 8
int DOS_INT
mov al,dl
cbw
ret
endif
;
; mem_alloc(BYTE FAR * NEAR * bufaddr, UWORD * bufsize, UWORD min, UWORD max);
;
; max 10[bp]
; min 08[bp]
; bufsize 06[bp]
; buffadr 04[bp]
;
Public _mem_alloc
;---------
_mem_alloc:
;---------
push bp
mov bp,sp
mov bx,10[bp] ; Start with request maximum size
mem_all10:
mov ah,MS_M_ALLOC ; Attempt to allocate the maximum
int DOS_INT ; memory requested by the user.
jnc mem_all20 ; Allocation OK
cmp bx,08[bp] ; Is this less than the requested
jae mem_all10 ; No then allocate this amount
xor ax,ax ; Force the Buffer address and Buffer
mov bx,ax ; Size to Zero
mem_all20:
mov cx,bx ; Save the Buffer Size
mov bx,04[bp] ; Update the Buffer Address
mov word ptr 00[bx],0 ; Offset 0
mov word ptr 02[bx],ax ; Segment AX
mov bx,06[bp] ; Now Update the Buffer Size
mov word ptr 00[bx],cx ; and return to the caller
pop bp
ret
;
; mem_free(BYTE FAR * NEAR * bufaddr);
;
; buffadr 04[bp]
;
Public _mem_free
;---------
_mem_free:
;---------
push bp
mov bp,sp
xor ax,ax
mov bx,04[bp] ; Get the Buffer Pointer address
xchg ax,word ptr 02[bx] ; and from this the segment of the
cmp ax,0 ; allocated memory. If the memory
jz mem_free10 ; has already been freed the quit
push es ; Otherwise Free the Memory
mov es,ax
mov ah,MS_M_FREE
int DOS_INT
pop es
mem_free10:
pop bp
ret
Public _msdos
;-------
_msdos:
;-------
push bp
mov bp,sp
push si
push di
mov ah,4[bp]
mov dx,6[bp]
int DOS_INT
pop di
pop si
pop bp
ret
Public _ioctl_ver
;---------
_ioctl_ver:
;---------
ifdef DOSPLUS
mov ax,4452h ; Get DOS Plus BDOS version Number
else
mov ax,4451h ; Get Concurrent BDOS Version
endif
int DOS_INT ; Real DOS returns with Carry Set
jc cdos_v10
and ax,not 0200h ; Reset the Networking Bit
ret
cdos_v10:
xor ax,ax
ret
ifdef DOSPLUS
;
; Get CodePage information form the system. Return both the currently
; active CodePage and the System CodePage.
;
; ms_x_getcp(&globalcp, &systemcp);
;
Public _ms_x_getcp
;-----------
_ms_x_getcp:
;-----------
push bp
mov bp,sp
mov ax,MS_X_GETCP ; Get the CodePage Information
int DOS_INT ; and return an error if not
jc ms_x_getcp10 ; supported.
mov ax,bx ; Now update the callers
mov bx,04[bp] ; Global and System Codepage
mov word ptr [bx],ax ; variables
mov bx,06[bp]
mov word ptr [bx],dx
xor ax,ax
ms_x_getcp10:
neg ax ; Negate the error code has
pop bp ; no effect on 0
ret
;
; Change the current CodePage
;
; ms_x_setcp(globalcp);
;
Public _ms_x_setcp
;-----------
_ms_x_setcp:
;-----------
push bp
mov bp,sp
mov bx,04[bp] ; Get the requested CodePage
mov ax,MS_X_SETCP ; and make this the default
int DOS_INT
jc ms_x_getcp10
xor ax,ax
pop bp
ret
endif
endif
ifdef CDOSTMP
Public _ms_drv_set
;-----------
_ms_drv_set:
;-----------
push bp
mov bp,sp
mov dl,04[bp] ; Get the Specified drive
or dl,80h ; Prevent any Select Errors
mov cl,DRV_SET ; and go select the bugger
int BDOS_INT
pop bp
ret
Public _ms_drv_get
;-----------
_ms_drv_get:
;-----------
mov cl,DRV_GET ; Return the Currently selected
int BDOS_INT ; disk drive
cbw
ret
Public _ms_drv_space
;------------
_ms_drv_space:
;------------
;
; ret = _ms_drv_space (drive, &free, &secsiz, &nclust);
; where: drive = 0, 1-16 is drive to use
; free = free cluster count
; secsiz = bytes/sector
; nclust = clusters/disk
; ret = sectors/cluster -or- (0xFFFFh)
push bp
mov bp,sp
mov al,OK_RF ; Retry or Fail
call fdos_retry
mov FD_FUNC, FD_DISKINFO
mov ax,04[bp]
mov FD_DRIVE,ax
call fdos_entry
or ax,ax ; Check for Errors
mov ax,0FFFFh
jnz ms_drv_exit ; Error Exit
push es ; Save ES
push di
les di,FD_DPB ; Get the DPB Address
mov ax,es:DDSC_FREE[di] ; Get the number of free
mov bx,06[bp] ; clusters on the drive
mov [bx],ax
mov ax,es:DDSC_SECSIZE[di] ; Get the Physical Sector Size
mov bx,08[bp] ; in bytes
mov [bx],ax
mov ax,es:DDSC_NCLSTRS[di] ; Get the disk size in
mov bx,10[bp] ; clusters and save in DX
mov [bx],ax
mov al,es:DDSC_CLMSK[di] ; Get the sectors per Cluster -1
cbw ; and save in AX
inc ax
pop di
pop es
ms_drv_exit:
pop bp
CRET 8
Public _ms_s_country
;------------
_ms_s_country:
;------------
push bp
mov bp,sp
mov ax,04[bp] ; Get the data Block Offset
mov cd_country,0 ; Get the Current Country
mov cd_codepage,0 ; Current CodePage
mov cd_table,0 ; Country Information
mov cd_offset,ax ; Save the Buffer Offset
mov cd_segment,ds ; and the Buffer Segment
mov dx,dataOFFSET country_data
mov cl,S_GETCOUNTRY ; Get the country information
int BDOS_INT ; and return the current country
pop bp ; code to the caller
CRET 2
Public _ms_x_mkdir
;----------
_ms_x_mkdir:
;----------
push bp
mov bp,sp
mov al,OK_RIF ; Retry, Ignore or Fail
call fdos_retry
mov FD_FUNC,FD_MKDIR ; Make Directory
mkdir_10:
mov ax,04[bp]
mov FD_NAMEOFF,ax
mov FD_NAMESEG,ds
call fdos_entry
pop bp
CRET 2
Public _ms_x_rmdir
;----------
_ms_x_rmdir:
;----------
push bp
mov bp,sp
mov al,OK_RIF ; Retry, Ignore or Fail
call fdos_retry
mov FD_FUNC,FD_RMDIR
jmp mkdir_10
Public _ms_x_chdir
;----------
_ms_x_chdir:
;----------
push bp
mov bp,sp
mov al,OK_RF ; Retry or Fail
call fdos_retry
mov FD_FUNC,FD_CHDIR
jmp mkdir_10
Public _ms_x_creat
;----------
_ms_x_creat:
;----------
push bp
mov bp,sp
mov al,OK_RF ; Retry or Fail
call fdos_retry
mov FD_FUNC,FD_CREAT
jmp ms_open_creat
Public _ms_x_open
;---------
_ms_x_open:
;---------
push bp
mov bp,sp
mov al,OK_RF ; Retry or Fail
call fdos_retry
mov FD_FUNC,FD_OPEN
ms_open_creat:
mov ax,4[bp]
mov FD_NAMEOFF,ax
mov FD_NAMESEG,ds
mov ax,6[bp] ; get mode for new file (CREAT)
mov FD_MODE,ax ; or the OPEN mode
call fdos_entry ; Call the FDOS and return either
pop bp ; a handle or error code
CRET 4
Public _ms_x_close
;----------
_ms_x_close:
;----------
push bp
mov bp,sp
mov al,OK_RIF ; Retry, Ignore or Fail
call fdos_retry
mov ax,4[bp] ; get the open handle
mov FD_FUNC,FD_CLOSE
mov FD_HANDLE,ax
call fdos_entry
pop bp
CRET 2
Public _ms_x_unique
;----------
_ms_x_unique:
;----------
push bp
mov bp,sp
mov al,OK_RF ; Retry or Fail
call fdos_retry
mov FD_FUNC,FD_MKTEMP
jmp ms_open_creat
Public _ms_x_fdup
;----------
_ms_x_fdup:
;----------
push bp
mov bp,sp
mov al,OK_RIF ; Retry, Ignore or Fail
call fdos_retry
mov FD_FUNC,FD_FDUP
mov ax,4[bp] ; get the destination handle
mov FD_NEWHND,ax
mov ax,6[bp] ; Get the current handle
mov FD_HANDLE,ax
call fdos_entry
pop bp
CRET 4
Public _far_read
;---------
_far_read:
;---------
push bp
mov bp,sp
mov al,OK_RF ; Retry or Fail
call fdos_retry
mov FD_FUNC,FD_READ
jmp far_read_write
Public _far_write
;----------
_far_write:
;----------
push bp
mov bp,sp
mov al,OK_RIF ; Retry, Ignore or Fail
call fdos_retry
mov FD_FUNC,FD_WRITE
far_read_write:
mov ax,4[bp] ; get file handle
mov FD_HANDLE,ax
mov ax,6[bp] ; get buffer offset address
mov FD_BUFOFF,ax
mov ax,8[bp] ; get buffer Segment address
mov FD_BUFSEG,ax
mov ax,10[bp] ; get byte count
mov FD_COUNT,ax
call fdos_entry
or ax,ax
jnz far_rw_fail
mov ax,FD_COUNT ; Get the Byte Count
far_rw_fail:
pop bp
CRET 6
Public _ms_x_read
;---------
_ms_x_read:
;---------
push bp
mov bp,sp
mov al,OK_RF ; Retry or Fail
call fdos_retry
mov FD_FUNC,FD_READ
jmp ms_read_write
Public _ms_x_write
;----------
_ms_x_write:
;----------
push bp
mov bp,sp
mov al,OK_RIF ; Retry, Ignore or Fail
call fdos_retry
mov FD_FUNC,FD_WRITE
ms_read_write:
mov ax,4[bp] ; get file handle
mov FD_HANDLE,ax
mov ax,6[bp] ; get buffer address
mov FD_BUFOFF,ax
mov FD_BUFSEG,ds
mov ax,8[bp] ; get byte count
mov FD_COUNT,ax
call fdos_entry
or ax,ax
jnz ms_rw_fail
mov ax,FD_COUNT ; Get the Byte Count
ms_rw_fail:
pop bp
CRET 6
Public _ms_x_unlink
;-----------
_ms_x_unlink:
;-----------
push bp
mov bp,sp
mov al,OK_RIF ; Retry, Ignore or Fail
call fdos_retry
mov FD_FUNC,FD_UNLINK
jmp mkdir_10
Public _ms_x_lseek
;----------
_ms_x_lseek:
;----------
push bp
mov bp,sp
mov al,OK_RIF ; Retry, Ignore or Fail
call fdos_retry
mov FD_FUNC,FD_LSEEK ; get the function
mov ax,4[bp] ; get the file handle
mov FD_HANDLE,ax
mov ax,6[bp] ; get the offset
mov word ptr FD_OFFSET+0,ax
mov ax,8[bp]
mov word ptr FD_OFFSET+2,ax
mov ax,10[bp] ; get the seek mode
mov FD_METHOD,ax
call fdos_entry
cwd
or ax,ax
jnz ms_lseek_fail ; skip if errors
mov ax,word ptr FD_OFFSET+0 ; Return the New Location
mov dx,word ptr FD_OFFSET+2
ms_lseek_fail:
mov bx,dx ; AX:BX = DRC long return
pop bp
CRET 8
Public _ms_x_ioctl
;----------
_ms_x_ioctl:
;----------
push bp
mov bp,sp
mov al,OK_RF ; Retry or Fail
call fdos_retry
mov ax,4[bp] ; get Enquiry Handle
mov FD_FUNC,FD_IOCTL ; Use the IOCTL function
mov FD_HANDLE,ax ; For Handle AX
mov FD_CTLFUNC,0000 ; Get the Handle Status
mov FD_CTLSTAT,0 ; Invalidate CTLSTAT
call fdos_entry ; Call the FDOS
mov ax,FD_CTLSTAT ; and return the STATUS
pop bp
CRET 2
Public _ms_x_setdev
;------------
_ms_x_setdev:
;------------
push bp
mov bp,sp
mov al,OK_RF ; Retry or Fail
call fdos_retry
mov ax,4[bp] ; get Handle
mov FD_HANDLE,ax
mov FD_FUNC,FD_IOCTL ; Use the IOCTL function
mov FD_CTLFUNC,1 ; Set device info
mov ax, 6[bp] ; status to set
sub ah, ah
mov FD_CTLSTAT,ax
call fdos_entry ; Call the FDOS
mov ax,FD_CTLSTAT ; and return the STATUS
pop bp
CRET 2
Public _ms_x_chmod
;----------
_ms_x_chmod: ; ms_x_chmod(path, attrib, get/set)
;----------
push bp
mov bp,sp
mov al,OK_RIF ; Retry, Ignore or Fail
call fdos_retry
mov FD_FUNC,FD_CHMOD
mov ax,4[bp] ; Get the FileName
mov FD_NAMEOFF,ax
mov FD_NAMESEG,ds
mov ax,6[bp] ; Get the Required Attributes
mov FD_ATTRIB,ax
mov ax,8[bp] ; Finally Get the GET/SET flag
mov FD_FLAG,ax
call fdos_entry ; Returns with AX equal to the
or ax,ax ; error code or with the file
js chmod10 ; attributes.
mov ax,FD_ATTRIB
chmod10:
pop bp
CRET 6
Public _ms_x_curdir
;-----------
_ms_x_curdir:
;-----------
push bp
mov bp,sp
mov al,OK_RF ; Retry or Fail
call fdos_retry
mov FD_FUNC,FD_GETDIR
mov ax,04[bp] ; Get the drive
mov FD_DRIVE,ax
mov bx,06[bp] ; and then the path
mov byte ptr [bx],0 ; Put a Zero byte in the buffer in
mov FD_PATHOFF,bx ; case the command fails and the
mov FD_PATHSEG,ds ; user selects the FAIL Option
call fdos_entry
pop bp
CRET 4
;
; ms_x_expand(dstbuf, srcbuf) returns the full path of SRCBUF
;
Public _ms_x_expand
;-----------
_ms_x_expand:
;-----------
push bp
mov bp,sp
mov al,OK_RF ; Retry or Fail
call fdos_retry
mov FD_FUNC,FD_EXPAND
mov ax,06[bp] ; Get Source Buffer Offset
mov FD_ONAMEOFF,ax
mov FD_ONAMESEG,ds
mov bx,04[bp] ; Get the destination string
mov byte ptr [bx],0 ; address and force it to be a NULL
mov FD_NNAMEOFF,bx ; terminated string in case of errors
mov FD_NNAMESEG,ds
call fdos_entry
pop bp
CRET 4
Public _ms_x_wait
;---------
_ms_x_wait: ; retrieve child return code
;---------
mov cl,P_EXITCODE ; Return the Exit Code
mov dx,0FFFFh ; Get the Exit Code
int BDOS_INT
CRET 0
Public _ms_x_first
;----------
_ms_x_first:
;----------
push bp
mov bp,sp
mov dx,8[bp] ; get DMA buffer address
mov cl,F_DMAOFF
call bdos_entry
mov dx,ds ;##jc##
mov cl,F_DMASEG ;##jc##
call bdos_entry ;##jc##
mov al,OK_RF ; Retry or Fail
call fdos_retry
mov FD_FUNC,FD_FFIRST ; Search First
mov ax,04[bp] ; Get the FileName
mov FD_NAMEOFF,ax
mov FD_NAMESEG,ds
mov ax,06[bp] ; Get the Attributes
mov FD_ATTRIB,ax
mov FD_COUNT, 0 ; Search for a File at a time
call fdos_entry
cmp ax,1 ; Did we match 1 entry
jnz ms_x_f10 ; No so return Error Code
mov ax,0 ; Return Zero on sucess
ms_x_f10:
pop bp
CRET 6
Public _ms_x_next
;---------
_ms_x_next:
;---------
push bp
mov bp,sp
mov dx,4[bp] ; get DMA buffer address
mov cl,F_DMAOFF
call bdos_entry
mov dx,ds ;##jc##
mov cl,F_DMASEG ;##jc##
call bdos_entry ;##jc##
mov al,OK_RF ; Retry or Fail
call fdos_retry
mov FD_FUNC,FD_FNEXT ; Search Next
mov FD_NEXTCNT, 0 ; Search for a File at a time
call fdos_entry
cmp ax,1 ; Did we match 1 entry
jnz ms_x_n0 ; No so return Error Code
mov ax,0 ; Return Zero on sucess
ms_x_n0:
pop bp
CRET 2
Public _ms_x_rename
;-----------
_ms_x_rename:
;-----------
push bp
mov bp,sp
mov al,OK_RIF ; Retry, Ignore or Fail
call fdos_retry
mov FD_FUNC,FD_RENAME
mov ax,04[bp] ; Get the Old Name
mov FD_ONAMEOFF,ax
mov FD_ONAMESEG,ds
mov ax,06[bp] ; Get the New Name
mov FD_NNAMEOFF,ax
mov FD_NNAMESEG,ds
call fdos_entry
pop bp
CRET 4
Public _ms_x_datetime
;-------------
_ms_x_datetime: ; ms_x_datetime (gsflag, h, &time, &date);
;-------------
push bp
mov bp,sp
mov al,OK_RIF ; Retry, Ignore or Fail
call fdos_retry
mov FD_FUNC,FD_DATETIME ; set/get Time Stamp
mov ax,4[bp] ; get/set subfunction (0/1)
mov FD_SFLAG,ax
mov ax,6[bp] ; get handle
mov FD_HANDLE,ax
mov bx,8[bp] ; get address of time
mov ax,[bx] ; get time
mov FD_TIME,ax ; and Save
mov bx,10[bp] ; get address of date
mov ax,[bx] ; get date
mov FD_DATE,ax
call fdos_entry
or ax,ax ; Skip if Failed
jnz ms_dt_ret
mov ax,FD_TIME
mov bx,8[bp] ; get time address
mov [bx],ax ; update time
mov ax,FD_DATE
mov bx,10[bp] ; get date address
mov [bx],ax ; update date
xor ax,ax
ms_dt_ret:
pop bp
CRET 8
;
; The following routines allow COMMAND.COM to manipulate
; the system time and date. Four functions are provided and
; these are GETDATE, SETDATE, GETTIME and SETTIME
;
; Date information is passed and return in a structure which
; has the following format.
;
; WORD Year (1980 - 2099)
; BYTE Month
; BYTE Day
; BYTE Day of the Week (Ignored on SET DATE)
Public _ms_getdate
;-----------
_ms_getdate:
;-----------
push bp
mov bp,sp
mov dx,04[bp] ; Get the structure address
mov cl,T_GETDATE ; and call the BDOS
call bdos_entry
pop bp
CRET 2
Public _ms_setdate
;----------
_ms_setdate:
;----------
push bp
mov bp,sp
mov dx,4[bp] ; and get the structure address
mov cl,T_SETDATE ; and call the BDOS to do the work
call bdos_entry ; Return 0 Good and FFFF Bad
pop bp
CRET 2
; Time information is passed and return in a structure which
; has the following format.
;
; BYTE Hours (0 - 23)
; BYTE Minutes (0 - 59)
; BYTE Seconds (0 - 59)
; BYTE Hundredths of a second (0 - 99)
Public _ms_gettime
;----------
_ms_gettime:
;----------
push bp
mov bp,sp
mov dx,04[bp] ; Get the Time Structure address
mov cl,T_GETTIME ; and call the OS
call bdos_entry
pop bp
CRET 2
Public _ms_settime
;----------
_ms_settime:
;----------
push bp
mov bp,sp
mov dx,4[bp] ; and get the structure address
mov cl,T_SETTIME ; and call the BDOS SET Time Function
call bdos_entry ; Return 0 Good and FFFF Bad
pop bp
CRET 2
Public _ms_f_verify
;-----------
_ms_f_verify:
;-----------
push bp
mov bp,sp
push es
mov ax,04[bp] ; Get the required state
les bx,_pd ; Update the Verify flag in
and es:P_SFLAG[bx],not PSF_VERIFY ; current PD
or ax,ax ; Set the Flag
jz ms_fv10 ; No
or es:P_SFLAG[bx],PSF_VERIFY ; Flag set in PD
ms_fv10:
pop es
pop bp
ret
Public _ms_f_getverify
;--------------
_ms_f_getverify:
;--------------
push es
xor ax,ax ; Assume the flag is RESET
les bx,_pd ; now test the state of the
test es:P_SFLAG[bx],PSF_VERIFY ; flag in the current PD
jz ms_fgv10 ; Verify = OFF
inc ax ; Verify = ON
ms_fgv10:
pop es
ret
;
; mem_alloc(BYTE FAR * NEAR * bufaddr, UWORD * bufsize, UWORD min, UWORD max);
;
; max 10[bp]
; min 08[bp]
; bufsize 06[bp]
; buffadr 04[bp]
;
Public _mem_alloc
;---------
_mem_alloc:
;---------
push bp
mov bp,sp
mov mpb_start,0
mov ax,08[bp] ; Get the Minimum and Maximum values
mov mpb_min,ax ; and fill in the parameter block
mov ax,10[bp]
mov mpb_max,ax
mov mpb_pdadr,0
mov mpb_flags,0
mov cx,M_ALLOC ; Call the Concurrent Allocate function
mov dx,dataOFFSET mpb_start ;
call bdos_entry
xor cx,cx ; Assume that the function fails
mov dx,cx ; and zero the start and size fields
cmp ax,0
jnz mem_all10
mov cx,mpb_min ; Get the Allocation Size
mov dx,mpb_start ; and the starting segment
mem_all10:
mov bx,04[bp] ; Update the Buffer Address
mov word ptr 00[bx],0 ; Offset 0
mov word ptr 02[bx],dx ; Segment DX
mov bx,06[bp] ; Now Update the Buffer Size
mov word ptr 00[bx],cx ; and return to the caller
pop bp
ret
;
; mem_free(BYTE FAR * NEAR * bufaddr);
;
; buffadr 04[bp]
;
Public _mem_free
;---------
_mem_free:
;---------
push bp
mov bp,sp
xor ax,ax
mov bx,04[bp] ; Get the Buffer Pointer address
xchg ax,word ptr 02[bx] ; and from this the segment of the
cmp ax,0 ; allocated memory. If the memory
jz mem_free10 ; has already been freed the quit
mov mfpb_start,ax ; Otherwise Free the Memory
mov mfpb_res,0
mov cx,M_FREE
mov dx,dataOFFSET mfpb_start
call bdos_entry
mem_free10:
pop bp
ret
;
; findfile(BYTE *loadpath, UWORD *loadtype)
;
Public _findfile
_findfile:
push bp
mov bp,sp
mov al,OK_RF ; Retry, Ignore or Fail
call fdos_retry
mov ax,word ptr 04[bp]
mov exec_pathoff,ax
mov exec_pathseg,ds
mov cx,P_PATH
mov dx,dataOFFSET exec_block
call ppath_entry
or ax,ax
jnz ff_error
mov al,exec_filetype
cbw
mov bx,word ptr 06[bp]
mov word ptr [bx],ax
xor ax,ax
ff_error:
pop bp
ret
;
fdos_retry:
xor ah,ah
mov valid,ax ; Save the Valid Error responses
pop retry_ip ; Get the return Address
mov retry_sp,sp ; and Stack Pointer
jmp retry_ip
;
; FDOS_ENTRY is an internal function entry point which makes the
; F_DOS function call. As the F_DOS data area used by COMMAND.COM
; is always FDOS_DATA.
;
; WORD PASCAL critical_error(error, valid, drive, mode, server);
;
; critical_error will return an WORD response which (R,I,A,F)
; after displaying the appropriate error message and get the
; correct response from the user.
;
fdos_entry:
mov cl,F_DOS
mov dx,dataOFFSET fdos_data
ppath_entry:
call bdos_entry
cmp ax,ED_LASTERROR ; Did an Error Occur
jb fdos_exit ; No So Exit OK
cmp crit_flg,TRUE ; Already in handler
jz fdos_exit ; Yes Skip Critical Error
cmp ax,ED_PROTECT ; Is this a Physical Error
jg fdos_exit ; if so then simulate a
cmp ax,ED_GENFAIL ; Critical Error by calling
jge fdos_e05 ; the COMMAND routine Critical
; error
cmp ax,ED_NETPWD ; Now check for DR-NET errors
jg fdos_exit ; if so then simulate a
cmp ax,ED_NETLOG ; Critical Error by calling
jge fdos_e05 ; the COMMAND routine Critical
; error
fdos_exit:
ret
fdos_e05:
push retry_ip ; Save Retry IP and SP and valid
push retry_sp ; responses
push valid
mov crit_flg,TRUE ; Start Critical Section
mov cx,es ; Save the Segment Regsiter
push ax ; Save the Error Code
push valid ; Save the Valid Responses (R,I,F)
les bx,_pd ; Get the PD address
mov es,es:P_UDA[bx] ; and then the UDA address
xor ah,ah ; Zero the top byte of AX and
mov al,es:byte ptr 15h ;;U_ERR_DRV ; Get the Failing Drive
push ax ; Save on the Stack
mov al,es:byte ptr 14h ;;U_ERR_RW ; Get the Error Mode
push ax ; and Save
mov ax,00FFH ; Default Server NO is (INVALID)
les bx,_pd ; Get the PD address Again
mov bx,es:P_NDA[bx] ; and then the NDA address
cmp bx,0 ; Are we attached to DR-NET
jz fdos_e08 ; NO
mov es,bx ; ES -> DR-Net NDA
mov al,es:byte ptr 0Ch ;; NDA_CXRTN
fdos_e08:
push ax ; Pass the DR-NET Server No.
mov es,cx ; Restore ES
call CRITICAL_ERR ; Handle the Critical Error. Parameters
; are removed by the CALLEE
mov crit_flg,FALSE ; Critical Section complete
pop valid ; Restore our original RETRY IP
pop retry_sp ; and SP values which have been
pop retry_ip ; corrupted by the "CRITICAL_ERROR"
; routine during message printing
cmp ax,0 ; Ignore the Error
jz fdos_exit ; Then Exit with no Error
cmp ax,1 ; Retry the Operation
jnz fdos_e10 ; using information saved by FDOS_RETRY
mov sp,retry_sp ; Reset the Stack Pointer
jmp retry_ip ; and retry the Operation
fdos_e10:
cmp ax,3 ; FAIL this function
mov ax,ED_FAIL ; Fail the function
jz fdos_exit ; Yes otherwise ABORT
call _int_break ; Simulate a Control C to terminate
; We are never coming back
;
; BDOS_ENTRY is the usual method of calling the Operating System.
; In order to provide a DOS compatible environment this function.
; does Control-C checking on function exit.
;
bdos_entry:
int BDOS_INT
push es
les bx,_pd ; Get our process descriptor address
test es:P_SFLAG[bx],PSF_CTLC ; Check if a Control-C has been typed
jnz bdos_e10 ; Jump to Abort Handler
mov bx,ax ; Restore BX and Return.
pop es
ret
bdos_e10:
and es:P_SFLAG[bx],not PSF_CTLC
pop es
bdos_e20:
mov cl,C_RAWIO ; Flush the Character buffer until
mov dl,0FFh ; Return the character or 00 if queue
int BDOS_INT ; is empty. Repeat till the Keyboard
or al,al ; Buffer has been flushed
jnz bdos_e20
push ds
push cs
pop ds
mov cl,C_WRITESTR
mov dx,offset break_str ; echo ^C to screen
int BDOS_INT
pop ds
call _int_break ; Place the Control Break Code on the
; Stack and the call the error handler
; ** We will never return **
break_str db '^C$'
endif
ifndef DOSPLUS
Public __BDOS
;-------
__BDOS:
;-------
push bp
mov bp,sp
push si
push di
mov cl,4[bp]
mov dx,6[bp]
int BDOS_INT
pop di
pop si
pop bp
ret
;
endif
ifdef DOSPLUS
ifndef EXT_SUBST
Public _physical_drvs ; Physical Drives returns a LONG
_physical_drvs: ; Vector with bits set for every drive
mov ax,0 ; start with drive A:
mov cx,16 ; check the first 16 drives
mov bx,0
p_d10:
push ax ; pass drive no. to _physical_drive
call _physical_drive ; call it
cmp ax,0 ; check return value
pop ax ; restore ax
jz p_d20 ; if zero skip setting the bit in
or bx,1 ; the bitmap
p_d20:
ror bx,1 ; shift bitmap right
inc ax ; next drive
loop p_d10 ; Loop 16 Times
mov cx,10 ; Finally check the last 10 drives
mov dx,0
p_d30:
push ax ; pass drive no. to _physical_drive
call _physical_drive ; call it
cmp ax,0 ; check return val
pop ax ; restore ax
jz p_d40 ; id zero skip setting the bit in
or dx,1 ; the bitmap
p_d40:
ror dx,1 ; shift bitmap right
inc ax ; next drive
loop p_d30 ; Loop 10 Times
mov cl,6 ; Now rotate the contents of
ror dx,cl ; DX 6 more times for correct
; alignment of the Physical Drive Vector
mov ax,bx
mov bx,dx ; Return the long value in both
; AX:BX and AX:DX
ret
Public _logical_drvs ; Logical Drives returns a LONG
_logical_drvs: ; vector with bits set for every
mov cx,16 ; check the first 16 drives
mov ax,0 ; start with drive A:
mov bx,ax
l_d10:
push ax ; pass the drive to _logical_drive
call _logical_drive ; call it
cmp ax,0 ; check return value
pop ax ; restore ax
jz l_d20 ; skip if zero return
or bx,1 ; set bit in bitmap
l_d20:
ror bx,1 ; shift bitmap right
inc ax ; next drive
loop l_d10 ; Loop 16 Times
mov cx,10 ; Finally check the last 10 drives
mov dx,0
l_d30:
push ax ; pass the drive to _logical_drive
call _logical_drive ; call it
cmp ax,0 ; check return value
pop ax ; restore ax
jz l_d40 ; skip if zero return
or dx,1 ; set bit in bitmap
l_d40:
ror dx,1 ; shift bitmap right
inc ax ; next drive
loop l_d30 ; Loop 10 Times
mov cl,6 ; Now rotate the contents of
ror dx,cl ; DX 6 more times for correct
; alignment of bits
mov ax,bx
mov bx,dx ; Return the long value in both
ret ; AX:BX and AX:DX
Public _network_drvs ; Network Drives returns a LONG
_network_drvs: ; vector with bits set for every drive
xor ax,ax ; Start with BX:AX as
mov bx,ax ; zeros.
mov cx,'Z'-'A' ; We look at drives A-Z
n_d10:
add ax,ax ; we move the dword vector
adc bx,bx ; one place left
push ax
push bx ; save the vector
mov ah,MS_X_IOCTL
mov al,9 ; is device local ?
mov bl,cl ; drive number in BL
int DOS_INT
pop bx
pop ax ; recover the vector
jc n_d20 ; if an error skip network bit
test dx,1000h ; is device local ?
jz n_d20 ; if not then
or ax,1 ; set bit for this drive
n_d20:
loop n_d10
mov dx,bx ; long value in both AX:BX and AX:DX
ret
public _physical_drive
_physical_drive PROC NEAR
; BOOLEAN physical_drive(WORD);
; returns true if given drive (0-25) is physical.
;
push bp
mov bp,sp
push ds
push es
push si
push di
push dx
push cx
push bx
mov bx,4[bp] ; get the drive number
inc bx ; A=1, B=2, etc
mov ax,4409h ; IOCTL Network/Local
int 21h ; do it
jc not_phys ; carry means invalid drive
and dx,1000h ;
cmp dx,0
jne not_phys ; its a network drive
mov ax,cs
mov ds,ax
mov es,ax
mov si,offset func60_in
mov di,offset func60_out
mov ax,4[bp] ; insert drive letter in input string
add al,'A'
mov [si],al ;
mov ah,60h ; Expand Path string
int 21h ; do it
jc not_phys ; carry set means invalid drive
mov ax,4[bp] ; if drive letter changes then drive is
add al,'A' ; substed
cmp al,cs:[func60_out]
jne not_phys
mov ax,-1
jmp phys_exit
not_phys:
mov ax,0
phys_exit:
pop bx
pop cx
pop dx
pop di
pop si
pop es
pop ds
pop bp
ret
func60_in db "d:con",0
func60_out db 0,0,0,0,0,0,0,0,0,0
_physical_drive ENDP
;
; This function translates a logical to physical drive.
;
Public _pdrive
;------
_pdrive:
;------
push bp
mov bp,sp
push ds
push es
push si
push di
mov ax,cs
mov ds,ax
mov es,ax
mov si,offset func60_in
mov di,offset func60_out
mov ax,4[bp] ; insert drive letter in input string
add al,'A'
mov [si],al
mov ah,60h ; Expand Path string
int 21h ; do it
mov ax,4[bp] ; assume invalid, hence no change
jc pdrive_exit ; carry set means invalid drive
mov al,cs:[func60_out]
sub al,'A'
pdrive_exit:
pop di
pop si
pop es
pop ds
pop bp
CRET 2
public _logical_drive
_logical_drive PROC NEAR
; BOOLEAN logical_drive(WORD);
; returns TRUE if given drive (0-25) is logical
;
push bp
mov bp,sp
push ds
push es
push si
push di
push dx
push cx
push bx
mov bx,4[bp] ; get the drive number
inc bx ; A=1, B=2, etc
mov ax,4409h ; IOCTL Network/Local
int 21h ; do it
jc not_logical ; carry means invalid drive
and dx,1000h ;
cmp dx,0
jne not_logical ; its a network drive
mov ax,cs
mov ds,ax
mov es,ax
mov si,offset func60_in
mov di,offset func60_out
mov ax,4[bp] ; insert drive letter in input string
add al,'A'
mov [si],al ;
mov ah,60h ; Expand Path string
int 21h ; do it
jc not_logical ; carry set means invalid drive
mov ax,4[bp] ; if drive letter changes then drive is
add al,'A' ; substed
cmp al,cs:[func60_out]
je not_logical
mov ax,-1
jmp logical_exit
not_logical:
mov ax,0
logical_exit:
pop bx
pop cx
pop dx
pop di
pop si
pop es
pop ds
pop bp
ret
_logical_drive ENDP
public _network_drive
_network_drive PROC NEAR
; BOOLEAN network_drive(WORD);
; returns TRUE if given drive (0-25) is networked
;
push bp
mov bp,sp
push dx
push cx
push bx
mov bx,4[bp] ; get the drive number
inc bx ; A=1, B=2, etc
mov ax,4409h ; IOCTL Network/Local
int 21h ; do it
jc not_networked ; carry means invalid drive
and dx,1000h ;
cmp dx,0
jne not_networked ; its a network drive
mov ax,-1
jmp network_exit
not_networked:
mov ax,0
network_exit:
pop bx
pop cx
pop dx
pop bp
ret
_network_drive ENDP
endif ;EXT_SUBST
else ;!DOSPLUS
Public _physical_drvs ; Physical Drives returns a LONG
_physical_drvs: ; Vector with bits set for every
mov cx,DRV_LOGINVEC ; Physical or Networked Drive
int BDOS_INT ; attached to the system
xor dx,dx ; Return the LONG value in both
mov bx,dx ; AX:DX and AX:BX for maximum
ret ; compatibility
Public _network_drvs ; Network Drives returns a LONG
_network_drvs: ; vector with bits set for every
push es ; physical drive which has been
mov ax,0 ; mapped to a remote DRNET server
mov dx,ax
les bx,_pd ; Get Our Process Descriptor
mov cx,es:P_NDA[bx] ; and then the NDA Segment
jcxz n_d20 ; Skip Drive Test if no NDA
mov es,cx ; Get the RCT Address
les bx,es:dword ptr 04h ;; NDA_RCT ; From the NDA
mov cx,16
n_d10:
test es:RCT_DSK[bx],080h ; Is this a Remote drive
jz n_d15 ; No
or ax,1 ; Set Drive Bit
n_d15:
ror ax,1 ; Rotate Drive Bit Vector
add bx,2 ; Update the Drive Pointer
loop n_d10 ; Loop Till Done
n_d20:
mov bx,dx ; Return the long value in both
pop es ; AX:BX and AX:DX
ret
ifndef EXT_SUBST
Public _logical_drvs ; Logical Drives returns a LONG
_logical_drvs: ; vector with bits set for every
push es
push si
push di
les si,_pd ; Get Our Process Descriptor
mov si,es:P_CAT[si] ; and then the address of the
mov cx,16 ; first HDS and check the first
mov ax,0 ; 16 Drives
mov bx,ax
l_d10:
mov di,es:word ptr [si] ; Has this drive got an HDS
test di,di ; then skip setting the bit in
jz l_d20 ; the vector register
cmp es:byte ptr [di],bl ; Is the HDS pointing to same drive
jz l_d20 ; Yes then this is a Physical Drive
or ax,1
l_d20:
ror ax,1
add si,2
inc bx
loop l_d10 ; Loop 16 Tines
mov cx,10 ; Finally check the last 10 HDS
mov dx,0
l_d30:
mov di,es:word ptr [si] ; Has this drive got an HDS
test di,di ; then skip setting the bit in
jz l_d40 ; the vector register
cmp es:byte ptr [di],bl ; Is the HDS pointing to same drive
jz l_d40 ; Yes then this is a Physical Drive
or dx,1
l_d40:
ror dx,1
add si,2
inc bx
loop l_d30 ; Loop 10 Tines
mov cl,6 ; Now rotate the contents of
ror dx,cl ; DX 6 more times for correct
; alignment of bits
pop di
pop si
pop es
mov bx,dx ; Return the long value in both
ret ; AX:BX and AX:DX
;
; This function use the CONCURRENT 5.xx CP/M function to translate
; a logical to physical drive.
;
Public _pdrive
;------
_pdrive:
;------
push bp
mov bp,sp
mov dl,4[bp] ; get the logical drive
mov cl,175 ; Logical to Physical Xlat
int BDOS_INT
cbw
pop bp
CRET 2
endif ;!EXT_SUBST
endif ;!DOSPLUS
Public _toupper
UCASE equ 18 ; offset of dword ptr to uppercase func
;-------
_toupper proc near
;-------
; Return the uppercase equivilant of the given character.
; The uppercase function defined in the international info block is
; called for characters above 80h.
;
; char ch; char to be converted
; char result; uppercase equivilant of ch
;
; result = toupper(ch);
push bp
mov bp, sp
mov ax, 4[bp]
mov ah, 0 ; al = character to be converted
cmp al, 'a' ; al < 'a'?
jb exit_toupper ; yes - done (char unchanged)
cmp al, 'z' ; al <= 'z'?
jbe a_z ; yes - do ASCII conversion
cmp al, 80h ; international char?
jb exit_toupper ; no - done (char unchanged)
; ch >= 80h -- call international routine
call dword ptr [_country+UCASE]
jmp exit_toupper
a_z:
; 'a' <= ch <= 'z' -- convert to uppercase ASCII equivilant
and al, 0DFh
exit_toupper:
pop bp
ret
_toupper endp
ifdef DOSPLUS
if 0
Public _hiload_status
;----------
_hiload_status:
;----------
push bp
mov bp,sp
mov dx,100h ; get hiload state
mov ax,(MS_X_IOCTL*256)+57h ; IO Control function
int DOS_INT ; do INT 21h
pop bp ;
ret
Public _hiload_set
;----------
_hiload_set:
;----------
push bp
mov bp,sp
mov dx,4[bp] ; get state
mov dh,2 ; set hiload state
mov ax,(MS_X_IOCTL*256)+57h ; IO Control function
int DOS_INT ; do INT 21h
pop bp ;
ret
endif
Public _get_upper_memory_link
_get_upper_memory_link:
mov ax,5802h
int 21h
cbw
ret
Public _set_upper_memory_link
_set_upper_memory_link:
push bp
mov bp,sp
mov bx,4[bp]
mov ax,5803h
int 21h
pop bp
ret
Public _get_alloc_strategy
_get_alloc_strategy:
mov ax,5800h
int 21h
ret
Public _set_alloc_strategy
_set_alloc_strategy:
push bp
mov bp,sp
mov bx,4[bp]
mov ax,5801h
int 21h
pop bp
ret
Public _alloc_region
_alloc_region:
push es
xor ax,ax
mov es,ax ; assume no block allocated
mov ah,MS_M_ALLOC
mov bx,1
int 21h ; allocate a small block
jc _alloc_region10
mov es,ax
mov ah,MS_M_SETBLOCK
mov bx,0FFFFh
int 21h ; find out how big the block is
mov ah,MS_M_SETBLOCK
int 21h ; now grow to take up the block
_alloc_region10:
mov ax,es ; return address of block
pop es
ret
Public _free_region
_free_region:
push bp
mov bp,sp
push es
mov es,4[bp]
mov ah,MS_M_FREE
int 21h ; free the block
pop es
pop bp
ret
endif
; The Double Byte Character Set lead byte table.
; Each entry in the table except the last specifies a valid lead byte range.
;
; 0 +---------------+---------------+
; | start of | end of | DBCS table entry 0
; | range 0 | range 0 |
; 2 +---------------+---------------+
; | start of | end of | DBCS table entry 1
; | range 1 | range 1 |
; +---------------+---------------+
; :
; n +---------------+---------------+
; | 0 | 0 | end of DBCS table
; | | |
; +---------------+---------------+
Public _dbcs_expected
_dbcs_expected proc near
;-------------
; Returns true if double byte characters are to be expected.
; A call to dbcs_init() MUST have been made.
; Entry
; none
; Exit
; ax = 1 - double byte characters are currently possible
; 0 - double byte characters are not currently possible
ifdef DOSPLUS
push ds
push si
lds si, dbcs_table_ptr ; DS:SI -> system DBCS table
lodsw ; ax = first entry in DBCS table
test ax, ax ; empty table?
jz de_exit ; yes - return 0 (not expected)
mov ax, 1 ; return 1 (yes you can expect DBCS)
de_exit:
pop si
pop ds
else
xor ax,ax ; CDOS doesn't support them
endif
ret
_dbcs_expected endp
Public _dbcs_lead
_dbcs_lead proc near
;---------
; Returns true if given byte is a valid lead byte of a 16 bit character.
; A call to init_dbcs() MUST have been made.
; Entry
; 2[bp] = possible lead byte
; Exit
; ax = 1 - is a valid lead byte
; 0 - is not a valid lead byte
ifdef DOSPLUS
push bp
mov bp, sp
push ds
push si
mov bx, 4[bp] ; bl = byte to be tested
lds si,dbcs_table_ptr ; ds:si -> system DBCS table
lodsw ; any entries ?
test ax,ax
jz dl_not_valid ; no DBC entries
dl_loop:
lodsw ; al/ah = start/end of range
test ax, ax ; end of table?
jz dl_not_valid ; yes - exit (not in table)
cmp al, bl ; start <= bl?
ja dl_loop ; no - try next range
cmp ah, bl ; bl <= end?
jb dl_loop ; no - try next range
mov ax, 1 ; return 1 - valid lead byte
dl_not_valid:
pop si
pop ds
pop bp
else
xor ax,ax ; CDOS doesn't support them
endif
ret
_dbcs_lead endp
PUBLIC _extended_error
_extended_error PROC NEAR
mov ah,59h
mov bx,0
int 21h
neg ax
ret
_extended_error ENDP
PUBLIC _get_lines_page
_get_lines_page PROC NEAR
push bp
push es
mov ax,1130h
mov bx,0
mov dx,24 ; preset dx to 24 in case function not supported
int 10h
mov ax,dx ; returns (no. rows)-1 in dx
inc ax
pop es
pop bp
ret
_get_lines_page ENDP
PUBLIC _get_scr_width
_get_scr_width PROC NEAR
push bp
mov ah,0fh
int 10h
xor al,al
xchg ah,al
pop bp
ret
_get_scr_width ENDP
PUBLIC _novell_copy
_novell_copy PROC NEAR
push bp
mov bp,sp
push si
push di
mov ax,11f0h
mov si,4[bp] ; si = source handle
mov di,6[bp] ; di = destination handle
mov dx,8[bp] ; lo word of source length
mov cx,10[bp] ; hi word of source length
clc ; start with carry cleared
int 2fh ; do it
jc novcop_failure ; carry set means novell couldn't handle it
cmp ax,11f0h
je novcop_failure ; ax hasn't changed, so novell isn't there
mov ax,1 ; success !
jmp novcop_exit
novcop_failure:
mov ax,0
novcop_exit:
pop di
pop si
pop bp
ret
_novell_copy ENDP
PUBLIC _call_novell
_call_novell PROC NEAR
push bp
mov bp,sp
push es
push si
push di
mov ah,8[bp]
mov al,0ffh
push ds
pop es
mov si,4[bp]
mov di,6[bp]
int 21h
cmp al,0
jne call_nov_err
jc call_nov_err
mov ax,0
jmp call_nov_exit
call_nov_err:
mov ah,0 ;; clear ah, BUT allow all ret' values in al
call_nov_exit:
pop di
pop si
pop es
pop bp
ret
_call_novell ENDP
PUBLIC _nov_station
_nov_station PROC NEAR
push bp
mov bp,sp
push si
mov ax,0eeffh
int 21h
cmp ax,0ee00h
je ns_err
mov si,4[bp]
mov [si],cx
mov 2[si],bx
mov 4[si],ax
mov ax,0
jmp ns_exit
ns_err:
mov ax,-1
ns_exit:
pop si
pop bp
ret
_nov_station ENDP
public _nov_connection
_nov_connection PROC NEAR
push es
push si
if 0
mov ax,0
mov es,ax
mov si,0
mov ax,0ef03h
int 21h
mov ax,es
cmp ax,0
jne nc_ok
cmp si,0
jne nc_ok
mov ax,-1
jmp nc_exit
nc_ok:
mov al,es:23[si]
mov ah,0
endif
mov ax,0dc00h
int 21h
jc nc_err
sub ah,ah
jmp nc_exit
nc_err:
mov al,-1;
nc_exit:
pop si
pop es
ret
_nov_connection ENDP
_TEXT ENDS
END