; 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