mirror of
https://github.com/SEPPDROID/DR-DOS-OpenDOS.git
synced 2025-10-22 07:54:28 +00:00
3838 lines
96 KiB
NASM
3838 lines
96 KiB
NASM
; File : $Workfile: CSTART.ASM$
|
||
;
|
||
; Description :
|
||
;
|
||
; Original Author : DIGITAL RESEARCH
|
||
;
|
||
; Last Edited By : $CALDERA$
|
||
;
|
||
;-----------------------------------------------------------------------;
|
||
; Copyright Work of Caldera, Inc. All Rights Reserved.
|
||
;
|
||
; THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
|
||
; PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
|
||
; ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
|
||
; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
|
||
; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
|
||
; HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
|
||
; AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
|
||
; AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
|
||
; COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
|
||
; CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
|
||
; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
|
||
; CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
|
||
; AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
|
||
; CIVIL LIABILITY.
|
||
;-----------------------------------------------------------------------;
|
||
;
|
||
; *** Current Edit History ***
|
||
; *** End of Current Edit History ***
|
||
;
|
||
; $Log$
|
||
; CSTART.ASM 1.2 97/03/21 15:01:01
|
||
; Added /n option to disable critical error handler
|
||
; CSTART.ASM 1.38 94/12/21 10:45:05
|
||
; Reduced Heap size to 860h just to be sure.
|
||
; CSTART.ASM 1.34 94/03/29 16:10:05
|
||
; _docmd_int2f returns 1 or 0 depending on whether or not the command
|
||
; is accepted.
|
||
; CSTART.ASM 1.31 93/11/18 18:50:18
|
||
; Fix HMA registration problem
|
||
; CSTART.ASM 1.30 93/11/09 00:00:14
|
||
; Shorten _ge_config_env
|
||
; CSTART.ASM 1.28 93/11/05 00:54:25
|
||
; move HMA registration code to where it's actually executed
|
||
; CSTART.ASM 1.27 93/11/04 23:39:11
|
||
; Fix problem with resident data relocation code
|
||
; CSTART.ASM 1.26 93/11/04 20:06:09
|
||
; int2E_far_entry now does CLI and STI the correct way round when loading
|
||
; SS and SP.
|
||
; CSTART.ASM 1.25 93/10/24 13:13:34
|
||
; Added strategy 'best fit upper mem'' & link upper mem'
|
||
; put_resident_high()
|
||
; CSTART.ASM 1.24 93/09/10 15:56:46
|
||
; CLS checks for ANSI using Int 2F/1A00
|
||
; CSTART.ASM 1.23 93/08/26 09:40:50
|
||
; Now use PSP for stack during func 4b exec. There's some debug
|
||
; code in case things screw up.
|
||
; CSTART.ASM 1.21 93/08/03 10:04:18
|
||
; Stopped using memory above A000 for transient portion because the
|
||
; stack was disappearing when MEMMAX -V executed.
|
||
; CSTART.ASM 1.20 93/07/05 08:35:00
|
||
; Now switch to a stack located at the top of conventional memory before
|
||
; calling INT 21 ah=4B.
|
||
; CSTART.ASM 1.19 93/05/24 11:38:22
|
||
; alloc_com_memory now allocates copy buffer by allocating largest possible
|
||
; block then shrinking it to the correct size. This prevents the buffer
|
||
; being located in upper memory after a HILOAD.
|
||
; CSTART.ASM 1.16 93/02/24 17:42:01
|
||
; int10_cls() no longer checks position of INT 29 vector.
|
||
; CSTART.ASM 1.12 92/11/17 14:26:40
|
||
; Change to set_reload_file to allow switches on COMSPEC line.
|
||
; CSTART.ASM 1.10 92/09/17 11:31:43
|
||
; INT 2e DS=SI=0 now works when we are relocated.
|
||
; CSTART.ASM 1.9 92/09/11 10:45:36
|
||
; our_cmd_int2f altered so we can support multi-line macros in DOSKEY.
|
||
; CSTART.ASM 1.8 92/08/06 09:55:22
|
||
; Correctly support INT 2F AH=AEh for EDOS. See _cmd_line_int2f.
|
||
; Int 2E DS=SI=0 causes batch processing to halt.
|
||
; CSTART.ASM 1.7 92/07/20 17:13:44
|
||
; Added the following maintanence source code changes:
|
||
; 29 Apr 92 Now sets Novell error mode to 00 on entry, and restores
|
||
; ; original mode on exit.
|
||
; 18 May 92 Added routine get_original_envsize, to use as default if
|
||
; ; /E option not used
|
||
; ENDLOG
|
||
|
||
page 62,132
|
||
title COMMAND.COM Startup Routines and Resident Section
|
||
;
|
||
; 7 Nov 87 Force the initial PATH specification to the root of the
|
||
; boot drive. Also add a new variable TEMPDRV which is
|
||
; Concurrents Temporary Drive.
|
||
;
|
||
; 10 Dec 87 If DRNET has been loaded then add the DRNET=x.x string to
|
||
; the initial environment.
|
||
; 25 Feb 88 Run the 2nd Phase RSP's before spawning the remaining TMPs
|
||
; 1 Mar 88 Initialize the AUTOLOGON and NODE variables for diskless
|
||
; workstation support. Support the NODE environment variable
|
||
; 21 Mar 88 Allow for all registers to be corrupted on return from the
|
||
; DOS EXEC function call.
|
||
; 5 Apr 88 Correctly handle incorrect command line length passed by
|
||
; FrameWork Install Program
|
||
; 13 Apr 88 Move Memory allocation code to DOSIF and initialise the
|
||
; default console in PD for SunRiver.
|
||
; 10 May 88 Clean-Up the segment grouping and force the CGROUP to be
|
||
; linked after the data for everything but the TMP. Add the
|
||
; INT10_CLS function for DOSPLUS
|
||
; 12 May 88 Cater for DesqView passing an environment segment of 0000
|
||
; 13 May 88 Alter FCB build to giver F & RED when /FRED typed in For FS.COM
|
||
; 19 May 88 Prevent CODE being moved to high memory if loaded as an .EXE
|
||
; or no initial environment is supplied
|
||
; 20 May 88 Move reload messages into the MESSAGE.C file.
|
||
; 24 May 88 Use the internal Critical Error handler and check for ABORT
|
||
; codes while in the Command Processor Code.
|
||
; 6 Jun 88 Move Command ReadLine down to resident code - so SK+ can
|
||
; overwrite the hi-mem portion.
|
||
; 16 Jun 88 VC_DATA now returns the Physical Console Number as well.
|
||
; 21 Jun 88 Add FARPTR routine which determines the correct segment to
|
||
; return to PRINTF based on the offset of a message.
|
||
; 22 Jun 88 remove environment & PSP setup & RSP spawning code
|
||
; for banked RSP support. Kludgey CDOS_EXEC code for banking
|
||
; 29 Jun 88 Modify MASTER_ENV so it can be called from C and change the
|
||
; exec code to use the internal FCB parsing.
|
||
; 30 Jun 88 Set the default PRINTER and AUX using the information in the
|
||
; INT17 and INT14 mapping arrays.
|
||
; 20 Jul 88 Increase HEAP Size to 0A00h for the TMP
|
||
; 9 Aug 88 Terminate the command line after a CR or LF for
|
||
; BitStream Fontware.
|
||
; 31 Aug 88 Make the READLINE function call from high memory so PolyTron
|
||
; PolyWindows can be invoked from the command line.
|
||
; 22 Sep 88 Always use INT_BREAK routine for Control Break Handling
|
||
; 03 Oct 88 Invalidate the Old Environment for Novell under CDOS.
|
||
; 09 Nov 88 Select the correct DR-DOS history Buffer.
|
||
; 15 Nov 88 Re-initilaise Interrupt handlers after an EXEC for Novell
|
||
; 21 Nov 88 Install Command Processor Backdoor but just terminate caller
|
||
; 13 Dec 88 Generate the FCBs for a DOS exec internally for compatibility
|
||
; with Novell Netware.
|
||
; 15 Dec 88 Force the default INT 22, 23, 24 and 2E handlers to be set
|
||
; relative to the PSP. Update PSP copies of interrupt 22, 23, 24
|
||
; if this is the root DOS process.
|
||
; 25 Jan 89 If new DRDOS internal data layout get the PD a new way
|
||
; 27 Feb 89 fix MAKE_FCB, use SI from F_PARSE if possible
|
||
; 15 Apr 89 INT2E handler
|
||
; 17 Apr 89 int10_cls: don't return to 25 lines if in 43 or 50 line mode
|
||
; 31 May 89 DRDOS get PD using new f4458 backdoor
|
||
; 6 Jun 89 int2e: amend our copy of command, not users command
|
||
; 19 Jun 89 Remove "Alternative" methods of getting PD address
|
||
; 14 Jul 89 SideKick Plus checksum only done if STDERR is to CON
|
||
; (so when LAPLINK does CTTY COM1 it goes quicker)
|
||
; 6 Sep 89 Call INT21/5D09,5D08 in readline
|
||
; 30 Oct 89 Throw away startup code (put it in STACK segment)
|
||
; 13 Nov 89 Relocate DRDOS resident code over command line/fcbs in PSP
|
||
; 30 Jan 90 in_exec is now incremented and decremented to allow
|
||
; novell menu program to exit successfully.
|
||
; 30 Jan 90 Added batch_seg_ptr before first occurance of string
|
||
; 'A:\COMMAND.COM' (reload_file). Novell uses it during
|
||
; remote boot.
|
||
; 31 Jan 90 restore_term_addr puts back old Int22/23/24 ready for
|
||
; an EXIT command (DESQview bug)
|
||
; If no environment make reload_file in root of default drive
|
||
; 7 Feb 90 Turn off HILOAD on DRDOS
|
||
; Add d2cgroupptr support routine (see COM.C)
|
||
; 27 Mar 90 turn history buffers to command when in readline, so COPY CON
|
||
; etc will use application buffers
|
||
; 30 Mar 90 Stop cleanly when we can't reload transient portion rather
|
||
; than overwriting other peoples memory and crashing
|
||
; 4 Apr 90 dbcs_init moved from DOSIF, use system table,
|
||
; throw away init code
|
||
; 12 Apr 90 changed for no inherited environment
|
||
; 18 Apr 90 add JW's changes to int10_cls to support JW's new VGA card
|
||
; 9 May 90 Int2E doesn't trash Int24, returns with CY clear
|
||
; 17 May 90 CLI/STI round stack swap in INT2E exit routine.
|
||
; 5 Jun 90 Int21/4458 checks CY before fetching PD, so if running on DOS
|
||
; we carry on into the C code which gives version error
|
||
; 12 Jun 90 master_env now leaves MS_M_STARTEGY alone, because Novell
|
||
; gets confused if it ends up high
|
||
; 3/Jul/90 DLS data into R_TEXT for Watcom C v7.0 (again - I originally
|
||
; did this on 20/Apr/90, but someone screwed up with the
|
||
; archive version managment).
|
||
; 2-Aug-90 RG-00- define LOGIN procedures for Stellar security
|
||
; 1-Sep-90 _msgfarptr added for DLS
|
||
; 13-Sep-90 COMSPEC=A:\COMMAND.COM even when CDOS.COM
|
||
; 21-Sep-90 Increase TMP heap size so we can save initial state for
|
||
; subsequent login's.
|
||
; 26-Sep-90 We now switch to our own psp during an INT 2Eh.
|
||
; This fixes bug experienced with NOVELL MENU.EXE on top of
|
||
; DR DOS 5.0.
|
||
; 11-Oct-90 CDOSTMP exec stashes unlinked MD in PSP for TSR auto-load
|
||
; 03-Dec-90 Stop corruption of DMD chain when allocating high memory for
|
||
; transient portion of command processor
|
||
; 11 dec 90 CDOS.COM switches to TMP history buffer
|
||
; 13 dec 90 save ES around TMP P_EXEC (DRNET sometimes trashes it)
|
||
; 17 dec 90 exec of CMD call io_pckbd with cl=40h (must be 24 line)
|
||
; 26/Feb/91 Increased _rld_msgs maximum text size from 100 to 120.
|
||
; 11/Mar/91 Added show_help function. COMMAND.COM is now really
|
||
; an EXE file with the help messages tagged onto the end.
|
||
; 25/Apr/91 Most of the resident code/data is now relocatable to high
|
||
; memory. Some Novell critical data is left in low memory.
|
||
; 15/May/91 Added dummy code to force at least one relocation item in
|
||
; .exe header so loader doesn't think file is EXEPACKed.
|
||
; 12/Jun/91 Added dummy code to allow Software Carousel to run.
|
||
; See int22_entry.
|
||
; 19 jun 91 disable control break until handler initialised
|
||
; 24/Jun/91 Changed memory allocation procedure on return from func 4B to
|
||
; allow Novell Remote Boot to work.
|
||
; 2 jul 91 our_cmd_int2f only has single parameter
|
||
; 26 jul 91 Novell dummy pipe filenames zero terminated
|
||
; 29 jul 91 A 1K far buffer is now allocated by alloc_com_memory. It is
|
||
; used by type, batch_read, and printf.
|
||
; 5 Aug 91 Call Get Extended Error (int 21 ah=59) after exec.
|
||
; 14 Aug 91 Put pointers to _batch, _batchflg, and _echoflg in low memory
|
||
; stub. This is primarily for Software Carousel.
|
||
; 4 Dec 91 Fixed problem with full environment trashing next DMD.
|
||
; 29 Apr 92 Rearranged DGROUP so that constant code and data appear after
|
||
; the stack - So that Multitasker need not save it.
|
||
; 10 Jun 92 show_help function now copes with doubled % characters.
|
||
;
|
||
;------------------------------------------------------------------------------
|
||
|
||
.xlist
|
||
include msdos.equ
|
||
include mserror.equ
|
||
include char.def
|
||
.list
|
||
|
||
|
||
; This is the offset in segment FFFF to which we will relocate.
|
||
; It is set to E0 to allow for a PCNFS bug
|
||
HISEG_OFF equ 0E0h
|
||
|
||
|
||
FALSE equ 0h
|
||
TRUE equ not FALSE
|
||
|
||
ThreeCOM equ TRUE
|
||
|
||
|
||
Copy_Buffer_Size equ 0C80h ; 50k of buffer space in paras
|
||
; matches MAX_COPYBUF in COMCPY.C
|
||
RLSTACK_SIZE equ 256+256 ; Reserve for ReadLine stack
|
||
; We need 260 bytes for possible
|
||
; buffer, plus a little stack
|
||
; If the stack overflows it isn't
|
||
; a disaster - we will just re-load
|
||
; COMMAND.COM
|
||
|
||
ifdef CDOSTMP
|
||
C_HEAP_SIZE equ 1200h ; C routine Heap Size - TMP has
|
||
else ; extra to save ENV in
|
||
;C_HEAP_SIZE equ 0800h ; C routine Heap Size
|
||
;endif ; (observed sizes 500h-600h - IJ)
|
||
C_HEAP_SIZE equ 0860h ; C routine Heap Size
|
||
; For safety increased that value as UNC filenames require 128 byte buffers
|
||
; allocated dynamically on tha stack. With respect to the observed sizes
|
||
; above it might be dangerous to leave that value at 0800h. I would have
|
||
; increased the value to 0A00 but then it does no longer fit into HMA. (JBM)
|
||
endif
|
||
|
||
ifdef DOSPLUS
|
||
include f52data.def
|
||
else
|
||
.xlist
|
||
include system.def
|
||
include pd.def
|
||
.list
|
||
|
||
XIOS_HISTBUF equ 44 ; Get the History Buffer Address
|
||
XIOS_PCKBD equ 32 ; Set keyboard/screen modes
|
||
|
||
NETMOD_BIT equ 040h ; Network Module in MODULE_MAP
|
||
|
||
; Concurrent DOS System Data Page Format
|
||
XIOS_ENTRY equ ds:dword ptr 0028h ; XIOS function Entry
|
||
CCPMSEG equ es:word ptr 0040h ; OS Starting Paragraph
|
||
MODULE_MAP equ es:byte ptr 0046h ; Concurrent Module Map
|
||
NVCNS equ es:byte ptr 0047h ; Number of Virtual Consoles
|
||
MFL equ es:word ptr 005Ah ; Memory Free List
|
||
RLR equ es:word ptr 0068h ; Ready List Root
|
||
VERSION equ es:word ptr 0078h ; OS Version String Offset
|
||
MWDR equ es:word ptr 0098h ; Memory Window Decriptor
|
||
BOOTDRV equ es:byte ptr 009Dh ; System Boot Drive
|
||
ENVSIZE equ es:word ptr 00B8h ; Environment Size Bytes
|
||
DRNET_NODE equ es:byte ptr 00BAh ; DR-NET Node Number
|
||
DRNET_FLAG equ es:byte ptr 00BB ; DR-NET Flags
|
||
V386_PTR equ es:word ptr 00C8h ; 386 Data pointer
|
||
|
||
CCBLIST equ es:word ptr 0C3Eh ; XIOS CCB$LIST
|
||
INT17_PTR equ es:word ptr 0C46h ; XIOS INT 17 Mapping Array
|
||
INT14_PTR equ es:word ptr 0C48h ; XIOS INT 14 Mapping Array
|
||
|
||
CCB_OWNER equ es:word ptr 0 ; CCB Owning Process
|
||
CCB_PCNS equ es:byte ptr 10 ; CCB Physical Console Number
|
||
CCB_VCNS equ es:byte ptr 11 ; CCB Virtual Console Number
|
||
|
||
MF_CODE equ 0004h ; MD flag bit
|
||
endif
|
||
;
|
||
; Standard definitions for PSP variable
|
||
;
|
||
PSP_TERM_IP equ es:word ptr 000Ah
|
||
PSP_PARENT equ es:word ptr 0016h
|
||
PSP_ENVIRON equ es:word ptr 002ch
|
||
|
||
|
||
ifndef DOSPLUS
|
||
; The following Macro takes one parameter which is the Concurrent DOS
|
||
; function number.
|
||
|
||
bdos MACRO func
|
||
ifnb <func>
|
||
mov cl,func
|
||
endif
|
||
int 224
|
||
ENDM
|
||
|
||
.xlist
|
||
include ccpm.equ
|
||
.list
|
||
endif
|
||
|
||
swap MACRO reg1, reg2
|
||
push reg1
|
||
push reg2
|
||
pop reg1
|
||
pop reg2
|
||
ENDM
|
||
|
||
page
|
||
ifdef CDOSTMP
|
||
;
|
||
; For the Concurrent DOS TMP the CGROUP segments are defined
|
||
; first so that the CGROUP appears first in the .EXE file and
|
||
; can be converted to a .COM by "RELOC" or "EXE2BIN". This .COM
|
||
; file is then converted to a .CMD by the COM2CMD utility which
|
||
; uses the data embeded at the start of the code to generate the
|
||
; right groups.
|
||
;
|
||
HGROUP GROUP HEADER
|
||
HEADER SEGMENT para public 'HEADER'
|
||
HEADER ENDS
|
||
|
||
DGROUP GROUP RSP_SEG,PD_SEG,UDA_SEG,NULL,EXEC_CODE,_DATA,DATA,CONST,FIXED,_BSS,HEAP,c_common,STACK,DYNAMIC
|
||
|
||
RSP_SEG SEGMENT para public 'CDOS_DATA'
|
||
RSP_SEG ENDS
|
||
PD_SEG SEGMENT para public 'CDOS_DATA'
|
||
PD_SEG ENDS
|
||
UDA_SEG SEGMENT para public 'CDOS_DATA'
|
||
UDA_SEG ENDS
|
||
NULL SEGMENT para public 'BEGDATA'
|
||
NULL ENDS
|
||
EXEC_CODE SEGMENT byte public 'DATA'
|
||
EXEC_CODE ENDS
|
||
_DATA SEGMENT byte public 'DATA'
|
||
_DATA ENDS
|
||
DATA SEGMENT byte public 'DATA'
|
||
DATA ENDS
|
||
CONST SEGMENT byte public 'CONST'
|
||
CONST ENDS
|
||
FIXED SEGMENT para public 'FDATA'
|
||
FIXED ENDS
|
||
_BSS SEGMENT word public 'BSS'
|
||
_BSS ENDS
|
||
HEAP SEGMENT word public 'BSS'
|
||
HEAP ENDS
|
||
c_common SEGMENT byte public 'BSS'
|
||
c_common ENDS
|
||
STACK SEGMENT para public 'BSS'
|
||
STACK ENDS
|
||
DYNAMIC SEGMENT para public 'DDATA'
|
||
DYNAMIC ENDS
|
||
endif
|
||
|
||
ifndef CDOSTMP
|
||
; The following declarations declare the presence and order of
|
||
; various data segments within the DATA Group of the command
|
||
; processor.
|
||
;
|
||
DGROUP GROUP R_TEXT, ED_TEXT, NULL, _DATA, DATA, CONST, FIXED, _BSS, HEAP, c_common, STACK, DYNAMIC
|
||
|
||
R_TEXT SEGMENT para public 'CDOS_DATA'
|
||
R_TEXT ENDS
|
||
NULL SEGMENT byte public 'BEGDATA'
|
||
NULL ENDS
|
||
_DATA SEGMENT byte public 'DATA'
|
||
_DATA ENDS
|
||
DATA SEGMENT byte public 'DATA'
|
||
DATA ENDS
|
||
CONST SEGMENT byte public 'CONST'
|
||
CONST ENDS
|
||
FIXED SEGMENT byte public 'FDATA'
|
||
FIXED ENDS
|
||
_BSS SEGMENT byte public 'BSS'
|
||
_BSS ENDS
|
||
HEAP SEGMENT byte public 'BSS'
|
||
HEAP ENDS
|
||
c_common SEGMENT byte public 'BSS'
|
||
c_common ENDS
|
||
STACK SEGMENT word public 'STACK'
|
||
STACK ENDS
|
||
ED_TEXT SEGMENT para public 'CDATA'
|
||
Public ed_text_start
|
||
ed_text_start label byte
|
||
ED_TEXT ENDS
|
||
DYNAMIC SEGMENT para public 'DDATA'
|
||
DYNAMIC ENDS
|
||
endif
|
||
|
||
CGROUP GROUP _TEXT, _MSG, _TEXTEND
|
||
_TEXT SEGMENT para public 'CODE'
|
||
ifdef DLS
|
||
extrn _my_dls_init:far
|
||
endif
|
||
_TEXT ENDS
|
||
|
||
_MSG SEGMENT byte public 'CODE'
|
||
_MSG ENDS
|
||
|
||
_TEXTEND SEGMENT para public 'CODE'
|
||
_TEXTEND ENDS
|
||
|
||
|
||
CEND GROUP ETEXT, ETEXTEND
|
||
ETEXT SEGMENT para public 'XEND'
|
||
ETEXT ENDS
|
||
ETEXTEND SEGMENT para public 'XEND'
|
||
ETEXTEND ENDS
|
||
|
||
|
||
codeOFFSET equ offset CGROUP:
|
||
dataOFFSET equ offset DGROUP:
|
||
endOFFSET equ offset CEND:
|
||
|
||
code_length equ codeOFFSET rlstack ; Total Code Length
|
||
real_code equ code_length - RLSTACK_SIZE
|
||
static_length equ dataOFFSET FIXED ; Static Data Length
|
||
dynamic_length equ dataOFFSET ed_text_start
|
||
total_length equ dataOFFSET DYNAMIC ; Total Data Length
|
||
cgroup_length equ codeOFFSET _TEXTEND
|
||
cend_length equ endOFFSET ETEXTEND
|
||
|
||
; help_length is an APPROXIMATE value, but it must be LARGER than the correct
|
||
; length of the help segment.
|
||
ifdef DLS
|
||
help_length equ 0A000h
|
||
else
|
||
help_length equ 05000h
|
||
endif
|
||
|
||
page
|
||
public __acrtused ; trick to force in startup
|
||
__acrtused = 9876h ; funny value not easily matched in SYMDEB
|
||
|
||
ifdef CDOSTMP
|
||
HEADER SEGMENT public 'HEADER'
|
||
dw 0EDCh ; Header Signature
|
||
dw offset HGROUP:CGROUP ; Code Group
|
||
dw real_code ; Real Code Size
|
||
dw offset HGROUP:DGROUP
|
||
dw total_length
|
||
dw static_length
|
||
HEADER ENDS
|
||
|
||
; These Segments are forced into the correct order for a CDOS
|
||
; Resident System Process. First the RSP header which contains
|
||
; the regeneration information required by GENSYS.
|
||
;
|
||
RSP_SEG SEGMENT
|
||
sysdatseg dw 0 ; system data segment
|
||
sdatvar dw 0047h ; # of system consoles
|
||
defconsole db 0,0 ; console # | copy #
|
||
dw 0,0
|
||
dw RSF_DYNAMIC+RSF_SPECIAL+RSF_ENVIRON
|
||
dw 0
|
||
dw 0
|
||
|
||
RSP_SEG ENDS
|
||
|
||
_DATA SEGMENT byte public 'DATA'
|
||
extrn _gp_far_buff:word
|
||
_DATA ENDS
|
||
|
||
else
|
||
R_TEXT SEGMENT
|
||
assume cs:DGROUP, ds:nothing, es:nothing, ss:nothing
|
||
|
||
ifdef WATCOMC
|
||
Public _small_code_ ; Watcom C requires this label to
|
||
_small_code_ label near ; be declared in the start-up module
|
||
else
|
||
ifdef MWC
|
||
Public _mwINIT ; MetaWare requires this label
|
||
_mwINIT label near ; to be declared in the start-up
|
||
; module
|
||
else
|
||
Public __cstart
|
||
__cstart label near ; to be declared in the start-up
|
||
; module
|
||
endif
|
||
endif
|
||
|
||
extrn _gp_far_buff:word
|
||
|
||
ifdef DOSPLUS
|
||
extrn com_criterr:near
|
||
endif
|
||
|
||
|
||
cstart: ; start address of all "C" programs
|
||
call near ptr getIP ; Push the IP register and Skip the
|
||
retIP: ; version control messages.
|
||
dw 0EDCh ; Digital Research Marker
|
||
dw code_length ; Length of the Code Group
|
||
;dw static_length ; Length of the Fixed Data Group
|
||
ifdef DLS
|
||
dw total_length
|
||
else
|
||
dw dynamic_length ; length of dynamic data
|
||
endif
|
||
dw total_length ; Minimum Length of the Runtime
|
||
; Data Group
|
||
|
||
reloc_off dw 0 ; offset of relocated resident code/data
|
||
reloc_seg dw 0 ; segment of relocated resident code/data
|
||
reloc_size dw 0 ; size of relocated resident code/data
|
||
|
||
public _batchptr_off
|
||
public _batchflg_off
|
||
public _echoflg_off
|
||
_batchptr_off dw 0 ; offset of _batch variable
|
||
_batchflg_off dw 0 ; offset of _batchflg variable
|
||
_echoflg_off dw 0 ; offset of _echoflg variable
|
||
|
||
; These are the entry points for INT 23 and INT 24. They will have JMPF
|
||
; instructions poked into them.
|
||
control_break_entry db 5 dup(90h)
|
||
crit_error_entry db 5 dup(90h)
|
||
|
||
|
||
; The call to MS_X_EXEC must be made from the same segment as the PSP.
|
||
; msdos_exec does a far jump to here and then we far jump back.
|
||
|
||
psp_dofunc4b:
|
||
mov ax,(MS_X_EXEC*256)
|
||
int DOS_INT
|
||
jmp i22_entry
|
||
|
||
; Software Carousel Version 5.0 looks for the following three instructions
|
||
; and assumes it is an entry point to int 22 code.
|
||
mov bx,0ffffh
|
||
mov ah,48h
|
||
int 21h
|
||
clc
|
||
i22_entry:
|
||
int22_entry db 0eah
|
||
dw dataOFFSET func4b_return
|
||
func4b_seg dw 0
|
||
|
||
int2E_entry db 0eah
|
||
dw dataOFFSET int2E_far_entry
|
||
int2E_seg dw 0
|
||
|
||
|
||
; IMPORTANT - batch_seg_ptr MUST be just before reload_file. - EJH
|
||
;
|
||
; ***** Do Not change the order of the following variables *****
|
||
;
|
||
|
||
batch_seg_ptr dw 0ffffh ; file filename. For novell remote
|
||
; boot support.
|
||
|
||
ifdef DOSPLUS
|
||
reload_file db 'A:\COMMAND.COM',0
|
||
else
|
||
ifdef NETWARE
|
||
reload_file db 'A:\NETWARE.COM',0
|
||
else
|
||
reload_file db 'A:\CDOS.COM',0
|
||
endif
|
||
endif
|
||
db (80-15) dup ('n') ; Expanded LoadPath
|
||
|
||
;cmdline db 128 dup ('c') ; Local Copy of Initial Command Line
|
||
|
||
; dummy pipe filenames for NOVELL
|
||
|
||
out_pipe db '_:/' , 0 , '_______.___',0
|
||
in_pipe db '_:/' , 0 , '_______.___',0
|
||
|
||
;
|
||
; ***** Do Not change the order of the preceeding variables *****
|
||
;
|
||
|
||
; This next bit forces hi_seg_start to be on a paragraph boundary
|
||
org HISEG_OFF
|
||
hi_seg_start label byte
|
||
|
||
; Himem Registration chain entry
|
||
himem_link_next dw 0
|
||
himem_link_size dw 0
|
||
db 5
|
||
|
||
public __psp
|
||
__psp dw 0
|
||
|
||
Public _batch_seg_ptr
|
||
_batch_seg_ptr dw dataOFFSET batch_seg_ptr
|
||
dw 0 ; segment will be set to low_seg
|
||
|
||
Public _cbreak_ok
|
||
|
||
_cbreak_ok db 0 ; set when ctrl-break handler initialised
|
||
|
||
; The following causes there to be at least one relocation item
|
||
; in the .exe header so the loader does not think the file is
|
||
; EXEPACKed.
|
||
mov ax,seg _batch_seg_ptr
|
||
|
||
R_TEXT ENDS
|
||
|
||
endif
|
||
|
||
_TEXT SEGMENT
|
||
ifdef CDOSTMP
|
||
assume cs:CGROUP, ds:DGROUP, ss:DGROUP
|
||
;
|
||
; This entry point is used when the startup is executed as an
|
||
; RSP. CS is CGROUP and DS is DGROUP. From here on we initialise
|
||
; internal data structures etc.
|
||
;
|
||
|
||
ifdef WATCOMC
|
||
Public _small_code_ ; Watcom C requires this label to
|
||
_small_code_ label near ; be declared in the start-up module
|
||
else
|
||
ifdef MWC
|
||
Public _mwINIT ; MetaWare requires this label
|
||
_mwINIT label near ; to be declared in the start-up
|
||
; module
|
||
else
|
||
Public __cstart
|
||
__cstart label near ; to be declared in the start-up
|
||
; module
|
||
endif
|
||
endif
|
||
|
||
cstart:
|
||
call RSP_start ; Push the IP register and Skip the
|
||
retIP: ; version control messages.
|
||
dw 0EDCh ; Digital Research Marker
|
||
dw code_length ; Length of the Code Group
|
||
dw static_length ; Length of the Fixed Data Group
|
||
dw total_length ; Minimum Length of the Runtime
|
||
; Data Group
|
||
else
|
||
extrn _int2e_handler:far
|
||
endif
|
||
extrn __main:far ; C main program
|
||
|
||
|
||
_TEXT ENDS
|
||
|
||
_DATA SEGMENT
|
||
;
|
||
; Data held in this segment remains in the resident portion of
|
||
; the program image is is not overlayed by transient programs
|
||
; loaded by COMMAND.COM. The variables here are private to the
|
||
; startup module.
|
||
;
|
||
psp_save_area dw 6 dup (?)
|
||
|
||
ifndef DOSPLUS
|
||
extrn _pd:dword ; Concurrent Process Descriptor
|
||
extrn _sysdat_seg:word ; Concurrent System Data Page
|
||
endif
|
||
|
||
extrn _n_option:word
|
||
;
|
||
; The following is the offset and segment of the C routine MAIN
|
||
; which is moved up in memory in order to accomodate the
|
||
; Environment variables and Resident Data area.
|
||
;
|
||
C_code_entry label dword
|
||
Public code_seg,low_seg
|
||
code_off dw codeOFFSET __main ; Offset of MAIN
|
||
code_seg dw ? ; Segment of MAIN
|
||
data_seg dw ? ; DGROUP segment
|
||
alloc_seg dw ? ; the start of hi mem allocated
|
||
low_seg dw ? ; segment of low memory stub.
|
||
|
||
ifdef CDOSTMP
|
||
|
||
Public __psp
|
||
__psp dw 0
|
||
|
||
cmd_histbuf dw 0 ; Command Processor History Buffer
|
||
prog_histbuf dw 0 ; Program History Buffer
|
||
|
||
mpb label word
|
||
mpb_start dw ?
|
||
mpb_min dw ?
|
||
mpb_max dw ?
|
||
mpb_pdadr dw ?
|
||
mpb_flags dw ?
|
||
|
||
sysdat dw ? ; Concurrent System Data Page
|
||
uda dw ? ; Concurrent User Data Area
|
||
;
|
||
; The following buffer is used by the P_EXEC function. Used
|
||
; by CDOS_EXEC to load DOS and CP/M programs.
|
||
;
|
||
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
|
||
exec_loadtype db ? ; EXEC or CHAIN to application
|
||
exec_clineoff dw ? ; ASCIIZ Command line Offset
|
||
exec_clineseg dw ? ; ASCIIZ Command Line Segment
|
||
|
||
exec label dword ; FAR pointer to EXEC routine
|
||
dw dataOFFSET cdos_exec
|
||
exec_seg dw ?
|
||
|
||
cmdline db 0 ; Blank Command Line
|
||
|
||
EXEC_CODE SEGMENT
|
||
|
||
Assume CS:DGROUP, DS:DGROUP, SS:DGROUP
|
||
|
||
err_tbl db 0 ; 00 Success
|
||
db -101 ; 01 System Call Not Implemented
|
||
db -102 ; 02 Illegal System Call
|
||
db ED_MEMORY ; 03 Cannot Find Memory
|
||
db -104 ; 04 Illegal Flag Number
|
||
db -105 ; 05 Flag Overrun
|
||
db -106 ; 06 Flag Underrun
|
||
db -107 ; 07 No Unused Queue Descriptors
|
||
db -108 ; 08 No free Queue Buffer
|
||
db -109 ; 09 Cannot find Queue
|
||
db -110 ; 10 Queue in Use
|
||
db -111 ; 11
|
||
db -112 ; 12 No Free Process Descriptors
|
||
db -113 ; 13 No Queue Access
|
||
db -114 ; 14 Empty Queue
|
||
db -115 ; 15 Full Queue
|
||
db -116 ; 16 CLI Queue missing
|
||
db -117 ; 17 No 8087 in system
|
||
db ED_DMD ; 18 No Unused Memory Descriptors
|
||
db -119 ; 19 Illegal Console Number
|
||
db -120 ; 20 No Process Descriptor Match
|
||
db -121 ; 21 No Console Match
|
||
db -122 ; 22 No CLI Process ??
|
||
db -123 ; 23 Illegal Disk Number
|
||
db -124 ; 24 Illegal FileName
|
||
db -125 ; 25 Illegal FileType
|
||
db -126 ; 26 Character Not Ready
|
||
db ED_BLOCK ; 27 Illegal Memory Descriptor
|
||
db -128 ; 28 Bad Return from BDOS load
|
||
db ED_FAIL ; 29 Bad Return from BDOS read
|
||
db ED_ACCESS ; 30 Bad Return from BDOS Open
|
||
db -131 ; 31 Null Command
|
||
db ED_ENVIRON ; 32 Not owner of resource
|
||
db -133 ; 33 No Cseg in Load File
|
||
db -134 ; 34 PD exists on Thread Root
|
||
db -135 ; 35 Could Not Terminate Process
|
||
db -136 ; 36 Cannot ATTACH to Process
|
||
db -137 ; 37 Illegal List Device Number
|
||
db ED_PASSWORD ; 38 Illegal Password
|
||
db -139 ; 39
|
||
db -140 ; 40 External Termination
|
||
db -141 ; 41 Fixup Error on Load
|
||
db -142 ; 42 Flag Set Ignored
|
||
db -143 ; 43 Illegal Aux Device Number
|
||
|
||
cdos2dos PROC NEAR
|
||
cmp ax,0000 ; Check for Success
|
||
jz c2d10 ; and skip lookup
|
||
lea bx,err_tbl ; xlat the error code in AL
|
||
xlat err_tbl ; into a Negated DOS compatible
|
||
mov ah,0FFH ; error code
|
||
c2d10:
|
||
ret
|
||
cdos2dos ENDP
|
||
|
||
; WORD FAR CDECL cdos_exec(BYTE *path, UWORD type, BYTE *line, BOOLEAN back);
|
||
;
|
||
; On Entry:
|
||
; back 10[bp]
|
||
; line 08[bp]
|
||
; type 06[bp]
|
||
; path 04[bp]
|
||
;
|
||
; ES = SYSDAT
|
||
;
|
||
; On Exit:
|
||
; AX = exit error code
|
||
;
|
||
cdos_exec PROC FAR
|
||
lea si,P_MEM[bx] ; SI -> root of MD's
|
||
ce_10: ; find our code segment
|
||
mov si,es:[si] ; get next memory descriptor
|
||
test si,si ; end of list?
|
||
jz ce_40 ; yes, we don't own any separate code
|
||
test es:word ptr 6[si],MF_CODE
|
||
jz ce_10 ; loop back if not code segment
|
||
mov si,es:8[si] ; get MPAD for code segment
|
||
lea di,P_MPAR[bx] ; get MPAD root
|
||
ce_20:
|
||
cmp si,es:[di] ; is this the predecessor?
|
||
je ce_30
|
||
mov di,es:[di] ; else check next MPAD
|
||
jmp short ce_20
|
||
ce_30: ; SI -> our MPAD, DI -> previous MPAD
|
||
xor ax,ax
|
||
xchg ax,es:[si] ; get next MPAD
|
||
mov es:[di],ax ; unlink our MPAD from list
|
||
ce_40:
|
||
push di
|
||
push si ; SI = 0 if no separate code alloc
|
||
|
||
push ds
|
||
mov ds,es:P_PSP[bx] ; point to our PSP
|
||
mov ds:word ptr [5eh],si ; stash TMP mpad away in here
|
||
pop ds
|
||
|
||
mov dx,198 ; Raise the priority of the TMP
|
||
bdos P_PRIORITY ; while we wait for the child
|
||
|
||
mov dx,dataOFFSET exec_block
|
||
push es ; do a P_EXEC but save /restore
|
||
bdos P_EXEC ; ES around it since DRNET trashes
|
||
pop es ; it sometimes.
|
||
|
||
mov ax,cx ; Get the Concurrent Error Code
|
||
call cdos2dos ; and convert to a standard DOS
|
||
push ax
|
||
; Error Code for COMMAND.RSP
|
||
test ax,ax ; If any errors occured during the
|
||
jnz ce_60 ; exec or the child process is not
|
||
cmp word ptr 10[bp],0 ; inheriting the console the do not
|
||
jnz ce_60 ; execute a Console Attach function
|
||
bdos C_ATTACH ; process to terminate
|
||
ce_60:
|
||
mov dx,200 ; Return to the normal priority
|
||
bdos P_PRIORITY ; now that we have the console back
|
||
pop ax
|
||
pop si
|
||
pop di
|
||
test si,si ; separate code allocation?
|
||
jz ce_50 ; no, don't have to un-kludge!
|
||
push ax
|
||
mov ax,es:[di] ; get link of previous MPAD
|
||
mov es:[si],ax ; link it to our MPAD
|
||
mov es:[di],si ; link our MPAD to previous MPAD
|
||
mov dx,1 ; make sure code gets banked in
|
||
bdos P_DELAY ; this gets us off/on RLR
|
||
pop ax
|
||
ce_50:
|
||
ret
|
||
cdos_exec ENDP
|
||
|
||
EXEC_CODE ENDS
|
||
|
||
_TEXT SEGMENT
|
||
assume cs:CGROUP, ds:DGROUP, es:nothing, ss:nothing
|
||
public _exec ; EXEC routine
|
||
|
||
;
|
||
; WORD CDECL exec(BYTE *path, UWORD type, BYTE *line, BOOLEAN back);
|
||
;
|
||
; On Entry:
|
||
; back 10[bp] ; This value is ignored for MSDOS_EXEC
|
||
; line 08[bp]
|
||
; type 06[bp]
|
||
; path 04[bp]
|
||
;
|
||
; On Exit:
|
||
; AX = exit error code
|
||
;
|
||
_exec:
|
||
;-----
|
||
push bp
|
||
mov bp,sp
|
||
push si
|
||
push di
|
||
mov ax,04[bp] ; Get the Full Command Name
|
||
mov exec_pathoff,ax
|
||
mov exec_pathseg,ds
|
||
|
||
mov ax,08[bp] ; and the Command Line
|
||
mov exec_clineoff,ax
|
||
mov exec_clineseg,ds
|
||
|
||
mov ax,06[bp] ; Get the Command Type (.CMD etc)
|
||
mov exec_filetype,al ; Save the Command type
|
||
mov exec_loadtype, 0 ; The default is to load the command
|
||
cmp word ptr 10[bp],0 ; and for the child to inherit the
|
||
jz exec_10 ; console
|
||
mov exec_loadtype,2
|
||
exec_10:
|
||
|
||
test al,al ; is command type a CMD
|
||
jnz exec20 ; no, skip XIOS call
|
||
mov ax,XIOS_PCKBD ; CMD's expect 24 lines
|
||
mov cl,40h ; so tell XIOS thats what we must have
|
||
mov dl,defconsole ; on this console
|
||
call xios
|
||
exec20:
|
||
|
||
les bx,_pd ; Get the process Descriptor Address
|
||
mov cx,prog_histbuf ; and force the system to use the
|
||
mov es:P_SB_SEG[bx],cx ; Program Level History Buffer
|
||
|
||
call exec ; do FAR call to cdos_exec
|
||
|
||
les bx,_pd ; Get the process Descriptor Address
|
||
mov cx,cmd_histbuf ; and force the system to use the
|
||
mov es:P_SB_SEG[bx],cx ; Command Level History Buffer
|
||
|
||
cmp exec_filetype,0 ; was it a CMD
|
||
jne exec30
|
||
push ax
|
||
mov ax,XIOS_PCKBD ; we are in must-be-24 line
|
||
mov cl,0 ; mode, get back to default mode
|
||
mov dl,defconsole ; for console number
|
||
call xios
|
||
pop ax
|
||
exec30:
|
||
pop di
|
||
pop si
|
||
pop bp
|
||
ret
|
||
|
||
_TEXT ENDS
|
||
|
||
|
||
Assume CS:DGROUP, DS:DGROUP, SS:DGROUP
|
||
else
|
||
;
|
||
; Novell 2.1 intercepts the DOSPLUS 4B00 return by updating the
|
||
; PSP USER_SS/SP and when it returns ALL registers except CS:IP
|
||
; have been corrupted.
|
||
;
|
||
extrn stack_min:word ; Minimum Stack Address
|
||
extrn heap_top:word
|
||
|
||
readline label dword ; FAR pointer to READLINE routine
|
||
dw dataOFFSET msdos_readline
|
||
readline_seg dw ?
|
||
|
||
critical dd ? ; Critical Error Handler Address
|
||
exec_sp dw ?
|
||
exec_ss dw ?
|
||
|
||
exec_block label byte
|
||
exec_env dw ? ; Environment Segment
|
||
exec_clineoff dw ? ; ASCIIZ Command line Offset
|
||
exec_clineseg dw ? ; ASCIIZ Command Line Segment
|
||
exec_fcb1off dw dataOFFSET fcb1 ; FCB1 Contents Offset
|
||
exec_fcb1seg dw ? ; FCB1 Contents Segment
|
||
exec_fcb2off dw dataOFFSET fcb2 ; FCB2 Contents Offset
|
||
exec_fcb2seg dw ? ; FCB2 Contents Segment
|
||
|
||
exec label dword ; FAR pointer to EXEC routine
|
||
dw dataOFFSET msdos_exec
|
||
exec_seg dw ?
|
||
|
||
msdos_exec_ret label dword ; FAR pointer to exit EXEC routine
|
||
dw codeOFFSET _exec_ret
|
||
msdos_exec_ret_seg dw ?
|
||
|
||
fcb1 db 16 dup (?) ; FCB1 Buffer
|
||
fcb2 db 16 dup (?) ; FCB2 Buffer
|
||
crc dw ? ; COMMAND.COM crc
|
||
|
||
; For Dual Language Support...
|
||
ifdef DLS
|
||
;;ED_TEXT SEGMENT para public 'CDATA'
|
||
|
||
Public _rld_msgs,_rld_text
|
||
_rld_msgs dw 120 ;RELOAD_LEN ; size of this message buffer
|
||
_reload_msgs dw 0 ; First part of Code reload prompt
|
||
_reload_msgf dw 0 ; Second part of Code reload prompt
|
||
_reload_msgm dw 0 ; Unlikely part of Code reload prompt
|
||
dw 0 ; end of list
|
||
_rld_text db 120 dup (?) ; message text is placed here
|
||
RELOAD_LEN equ $-_reload_msgs
|
||
;;ED_TEXT ENDS
|
||
else
|
||
extrn _reload_msgs:byte ; First part of Code reload prompt
|
||
extrn _reload_msgf:byte ; Second part of Code reload prompt
|
||
extrn _reload_msgm:byte ; No memory available message
|
||
endif
|
||
|
||
|
||
reload_flag db 0 ; Reloading Command Processor
|
||
in_exec db 0
|
||
high_code dw TRUE ; Enable High Code
|
||
exe_file dw FALSE ; True if COMMAND.COM is really an EXE
|
||
return_code dw ? ; Exec return code
|
||
net_error_mode db ?
|
||
|
||
; int2E data
|
||
|
||
i2e_lock dw 0 ; mutex flag
|
||
i2e_user_ss dw 0 ; users ss, sp
|
||
i2e_user_sp dw 0
|
||
i2e_stack dw 0
|
||
i2e_cmd dw 0 ; offset of local copy of command line
|
||
|
||
i2e_c_entry label dword
|
||
i2e_c_offs dw codeOFFSET _int2e_handler
|
||
i2e_c_seg dw ?
|
||
|
||
i2e_i23vec label dword
|
||
i2e_i23off dw ?
|
||
i2e_i23seg dw ?
|
||
|
||
i2e_i24vec label dword
|
||
i2e_i24off dw ?
|
||
i2e_i24seg dw ?
|
||
|
||
endif
|
||
_DATA ENDS
|
||
|
||
_BSS SEGMENT
|
||
Public _edata
|
||
_edata label BYTE ; end of data (start of bss)
|
||
_BSS ENDS
|
||
|
||
ETEXT SEGMENT
|
||
;
|
||
; The RLSTACK segment holds the stack used by the READLINE routine.
|
||
; This must be in High memory for the PolyTron PolyWindows product.
|
||
;
|
||
; "ETEXT" also forces the linker to pad the CGROUP to at least
|
||
; real_code bytes. Otherwise the file length can be upto 15 bytes
|
||
; shorter then real_code + total_length. This obviously causes
|
||
; problems with CALC_CRC and the file reloading.
|
||
;
|
||
db RLSTACK_SIZE dup(0CCh)
|
||
rlstack label word
|
||
|
||
ETEXT ENDS
|
||
|
||
ifdef CDOSTMP
|
||
STACK SEGMENT
|
||
|
||
Public _end
|
||
_end label BYTE ; end of bss (start of starup/stack)
|
||
|
||
db (C_HEAP_SIZE - 6) dup (0DDh) ; C Heap Area
|
||
stack_top label word
|
||
stack_ip dw ? ; Initial Offset
|
||
stack_cs dw ? ; Initial Code Segment (Unknown)
|
||
stack_flags dw ? ; Initial Flags (Unknown)
|
||
|
||
temp_buffer db 512 dup(0) ; temp far buffer for *gp_far_buff
|
||
|
||
STACK ENDS
|
||
else
|
||
|
||
STACK SEGMENT
|
||
|
||
stack_start:
|
||
; HEAP_TOP is initialised to _end so the _RELOAD_FILE and CMDLINE
|
||
; variables are allocated on the HEAP.
|
||
;
|
||
|
||
Public _end
|
||
_end label BYTE ; end of bss (start of startup/stack)
|
||
|
||
|
||
db 255,'3771146-XXXX-654321'
|
||
|
||
page
|
||
;
|
||
; The CS register is now adjusted so that this startup
|
||
; can be used in the form of an .EXE or .COM. Whatever the
|
||
; execution format of this file DS still points at the PSP
|
||
; but must be careful when resizing the RAM.
|
||
;
|
||
getIP PROC FAR
|
||
cld ; be sure of DIR flag...
|
||
pop di ; Get the Program Counter
|
||
sub di,dataOFFSET retIP ; Correct for retIP
|
||
mov cl,4 ; Convert Offset values to Segments
|
||
mov ax,cs ; Get the current CS
|
||
shr di,cl ; Convert Initial IP to Segment
|
||
add ax,di ; add to CS and save for CALLF to MAIN
|
||
push ax ; Save the New CS and the offset to
|
||
mov ax,dataOFFSET gotCS ; the next instruction and then execute
|
||
push ax
|
||
ret ; a RETF instruction to correct CS.
|
||
getIP ENDP
|
||
|
||
ifdef DOSPLUS
|
||
|
||
; Most of the PSP (FCB's and command buffer) is unused - we reclaim this space
|
||
; by relocating the resident part of COMMAND.COM
|
||
|
||
reloc_code:
|
||
;----------
|
||
; On Entry:
|
||
; CS = DGROUP, DS = PSP, ES = nothing
|
||
; On Exit:
|
||
; CS = relocated DGROUP
|
||
;
|
||
; We build a "REP MOVSB ! RETF 6" on the stack. We also fiddle the near return
|
||
; address into a FAR. We then setup our registers appropriately and execute
|
||
; this code.
|
||
;
|
||
if 1
|
||
ret
|
||
else
|
||
cmp ds:byte ptr 0080h,7fh ; discard garbage cmdline lengths
|
||
jb reloc_code10
|
||
ret
|
||
|
||
reloc_code10:
|
||
pop bx ; recover return offset
|
||
|
||
mov ax,0
|
||
push ax ; 0 (part of RETF 6)
|
||
mov ax,006cah
|
||
push ax ; RETF 6 on stack
|
||
|
||
mov ax,0a4f3h
|
||
push ax ; REP MOVSB on stack
|
||
|
||
mov al,ds:0080h ; Get the Command length
|
||
xor ah,ah
|
||
mov cl,4 ; convert AX to cmdline length
|
||
shr ax,cl ; in rounded down para's
|
||
add ax,9 ; keep at least this much
|
||
mov si,ds
|
||
add ax,si ; add in PSP
|
||
mov es,ax
|
||
mov cx,sp ; save address of code on stack
|
||
push ax
|
||
push bx ; new RETF address on stack
|
||
|
||
push ss
|
||
push cx ; address of CODE on stack
|
||
|
||
push cs
|
||
pop ds ; DS -> DGROUP
|
||
xor si,si ; setup DS:SI, ES:DI and CX
|
||
xor di,di ; ready to do REP MOVSB
|
||
mov cx,total_length ; DGROUP length
|
||
add cx,real_code ;+CGROUP length
|
||
|
||
db 0cbh ; RETF to code on stack
|
||
endif
|
||
endif
|
||
|
||
gotCS:
|
||
;out 0fdh,al ; for debug purposes
|
||
|
||
mov [__psp],ds ; Save our PSP in the local variable
|
||
ifdef DOSPLUS
|
||
mov ax,cs ; put our stack somewhere safe
|
||
mov ss,ax
|
||
mov sp,dataOFFSET rlstack
|
||
push ds
|
||
push di
|
||
call reloc_code ; relocate code over unused bit of PSP
|
||
pop di
|
||
pop ds
|
||
endif
|
||
ifdef DLS
|
||
call _my_dls_init
|
||
endif
|
||
|
||
mov [code_seg],cs ; Initialise the DATA segment address
|
||
mov [data_seg],cs ; and calculate the current address
|
||
mov [exec_seg],cs ; of the Code Segment
|
||
mov [readline_seg],cs ; use it to fixup some JMPFs
|
||
mov [_batch_seg_ptr+2],cs
|
||
mov [low_seg],cs ; we may be relocated to upper or high
|
||
; memory so remember the current segment
|
||
|
||
mov bx,cs ; Path up the JMPF instructions
|
||
sub bx,[__psp] ; around the MSDOS EXEC code to
|
||
mov cl,4
|
||
shl bx,cl
|
||
add cs:[exec_psp-2],bx
|
||
mov cs:[func4b_seg],cs
|
||
mov cs:[int2E_seg],cs
|
||
mov cs:[exec_psp],ds
|
||
|
||
cmp di,0000h ; Disable Code Relocation if we have
|
||
jnz gotCS_10 ; been loaded as an .EXE file
|
||
;;mov high_code,FALSE
|
||
|
||
mov exe_file,TRUE ; Remember we are an EXE
|
||
|
||
gotCS_10:
|
||
mov di,total_length
|
||
shr di,cl
|
||
add [code_seg],di
|
||
|
||
push ds ; Initialise the Checksum so we can
|
||
mov ds,[code_seg] ; check the integrity of the high
|
||
mov si,2 ; high copy of the command processor
|
||
call calc_crc ; code
|
||
pop ds
|
||
mov [crc],ax
|
||
|
||
mov ah,0ddh ; set Novell error mode
|
||
mov dl,0 ; to 00 - BAP
|
||
int 21h
|
||
mov net_error_mode,al ; save original error mode
|
||
|
||
call get_ds ; Get DGROUP value in AX
|
||
cli ; turn off interrupts
|
||
mov ss,ax ; SS = DGROUP
|
||
mov sp,dynamic_length ; Initialise SP
|
||
;mov sp,total_length
|
||
sti ; turn interrupts back on
|
||
|
||
assume ss:DGROUP
|
||
|
||
push ax
|
||
call handler_init ; Initialise the Control Break and
|
||
pop ax ; Critical Error Interrupt Vectors
|
||
|
||
mov si,total_length ; Get the DGROUP length in bytes
|
||
add si,code_length ; Add in the Code Length
|
||
mov cl,4 ; and convert to a paragraphs
|
||
shr si,cl
|
||
mov bx,ax ; Get the Current DS
|
||
sub bx,__psp ; and calculate DS - PSP Seg
|
||
add bx,si ; DS + Data length in Para's
|
||
mov es,__psp
|
||
mov ah,MS_M_SETBLOCK
|
||
int DOS_INT
|
||
|
||
call exec_name ; Get our Load Path from the environment
|
||
|
||
cmp high_code,FALSE ; Skip Memory check if HIGH_CODE
|
||
jz cstart_10 ; support has been disabled
|
||
|
||
mov high_code,FALSE ; Assume Failure.
|
||
|
||
call alloc_com_memory ; Allocate high memory for command.com
|
||
jnc carry_on
|
||
|
||
mov ax,cs ; if no memory and CS is nearing
|
||
cmp ax,8000h ; transient part abort and go home.
|
||
jb cstart_10
|
||
|
||
mov ah,4ch
|
||
int 21h
|
||
|
||
carry_on:
|
||
mov high_code,TRUE ; Set HIGH_CODE flag TRUE
|
||
push es ; Relocate the command processor code
|
||
push ds ; into high memory
|
||
mov es,ax ; es-> destination segment
|
||
mov di,0
|
||
mov si,0
|
||
mov ds,code_seg ; ds-> code to be moved
|
||
mov cx,real_code ; convert bytes to words
|
||
shr cx,1
|
||
rep movsw ; Move code up to high memory
|
||
mov code_seg,es ; update code_seg
|
||
|
||
pop ds
|
||
pop es
|
||
|
||
; Shrink memory containing low memory version of step aside code
|
||
mov si,total_length ; Get the DGROUP length in bytes
|
||
mov cl,4 ; and convert to a paragraphs
|
||
shr si,cl
|
||
call get_ds
|
||
mov bx,ax ; Get the Current DS
|
||
sub bx,__psp ; and calculate DS - PSP Seg
|
||
add bx,si ; DS + Data length in Para's
|
||
mov ah,MS_M_SETBLOCK
|
||
int DOS_INT
|
||
|
||
cstart_10:
|
||
ifdef DOSPLUS
|
||
mov ax,4457h ; terminate HILOAD operation
|
||
mov dx,200h
|
||
int DOS_INT
|
||
call dbcs_init ; initialise the DBCS support
|
||
endif
|
||
call get_cs
|
||
push ax
|
||
mov ax,codeOFFSET memory_init
|
||
push ax
|
||
db 0CBh ; a RETF instruction to correct CS.
|
||
|
||
page
|
||
;
|
||
; Build the full path and filename of this process using the
|
||
; loadpath attached to the environment. If no filename exists
|
||
; then prevent the Command Processor code from being located
|
||
; in high memory.
|
||
;
|
||
exec_name:
|
||
push es
|
||
mov es,__psp ; Get the PSP Segment Address
|
||
mov dx,PSP_ENVIRON ; Get the environment segment
|
||
cmp dx,0000 ; Have we got an environment ?
|
||
jz exec_n11 ; No prevent High Code Support
|
||
|
||
mov es,dx ; Scan through the environment and
|
||
mov di,0 ; determine the Environment size and
|
||
mov al,0 ; the Load file name
|
||
mov cx,7FFFh
|
||
exec_n05: ; Scan through the Environment
|
||
repne scasb ; searching for the 00 00 terminator
|
||
jcxz exec_n10 ; Terminate On CX == 0000
|
||
cmp es:byte ptr [di],al ; If the next byte is zero then this is
|
||
jnz exec_n05 ; then end of the environment
|
||
cmp es:word ptr 1[di],1 ; Are we pointing at the Control Word
|
||
jnz exec_n10 ; No then no Load Path exists
|
||
|
||
push ds
|
||
mov ds,dx ; DS -> Environment Segment
|
||
;call get_ds
|
||
;mov es,ax ; ES -> Command Processor Data Seg
|
||
mov es,[low_seg]
|
||
lea si,03[di] ; Fully expand the filename so the
|
||
mov di,dataOFFSET reload_file ; user can SUBST drives
|
||
mov ah,60h
|
||
int DOS_INT
|
||
exec_n15:
|
||
if 0
|
||
mov di,dataOFFSET reload_file ; this ASCIIZ string is on the heap
|
||
xor ax,ax ; so now we need to find out how
|
||
mov cx,-1 ; much space it takes up and reserve
|
||
repne scasb ; that amount of the heap
|
||
mov heap_top,di ; byte after the NUL is available
|
||
endif
|
||
pop ds
|
||
pop es
|
||
ret
|
||
|
||
exec_n10:
|
||
mov high_code,FALSE
|
||
exec_n11:
|
||
mov ah,MS_DRV_GET
|
||
int DOS_INT ; get default drive
|
||
mov es,[low_seg]
|
||
add es:reload_file,al ; and use that for the comspec
|
||
push ds
|
||
;call get_ds
|
||
;mov es,ax ; ES -> Command Processor Data Seg
|
||
jmp exec_n15
|
||
|
||
ifdef DOSPLUS
|
||
DI_BUF_PTR equ dword ptr -4 ; pointer to DBCS lead byte table
|
||
DI_BUF_ID equ byte ptr -5 ; buffer id
|
||
DI_BUF equ byte ptr -5 ; buffer
|
||
|
||
DI_LOCALS equ 5 ; No. bytes storage local to init_dbcs
|
||
|
||
_DATA SEGMENT byte public 'DATA'
|
||
|
||
Public dbcs_table_ptr
|
||
|
||
dbcs_table_ptr label dword
|
||
dbcs_table_off dw dataOFFSET dummy_dbcs_table
|
||
dbcs_table_seg dw 0
|
||
|
||
dummy_dbcs_table dw 0
|
||
|
||
_DATA ENDS
|
||
|
||
dbcs_init proc near
|
||
;--------
|
||
; To initialise the double byte character set (DBCS) lead byte table.
|
||
; MUST be called before the first call to dbcs_lead() or dbcs_expected().
|
||
; Entry
|
||
; none
|
||
; Exit
|
||
; none (side effect: DBCS table initialised)
|
||
|
||
push bp
|
||
mov bp, sp
|
||
sub sp, DI_LOCALS ; allocate local variables
|
||
push ds
|
||
push es
|
||
push di
|
||
push si
|
||
|
||
mov dbcs_table_seg, ds ; assume DBCS call will fail
|
||
|
||
mov ax, 06507h ; Extended Country Info: get DBCS ptr
|
||
mov bx, 0FFFFh ; codepage number: -1 for global cp
|
||
mov cx, 00005h ; size of info. buffer
|
||
mov dx, 0FFFFh ; country code: -1 for current country
|
||
lea di, DI_BUF[bp]
|
||
push ss
|
||
pop es ; es:di -> DI_BUF
|
||
int 21h ; returns with DI_BUF filled in
|
||
jc di_exit ; just exit if function fails
|
||
|
||
cmp DI_BUF_ID[bp], 7 ; is table for DBCS?
|
||
jne di_exit ; no - exit
|
||
les ax, DI_BUF_PTR[bp] ; es:ax -> system DBCS table
|
||
|
||
mov dbcs_table_off,ax
|
||
mov dbcs_table_seg,es ; fixup pointer to system DBCS table
|
||
|
||
di_exit:
|
||
pop si
|
||
pop di
|
||
pop es
|
||
pop ds
|
||
mov sp, bp
|
||
pop bp
|
||
ret
|
||
dbcs_init endp
|
||
|
||
endif
|
||
|
||
; I want to do
|
||
; db (C_HEAP_SIZE - 6 - ($ - stack_start)) dup (0DDh)
|
||
; but MASM requires dup's be absolute, so instead
|
||
rept C_HEAP_SIZE
|
||
if (offset $ - offset stack_start) LT (C_HEAP_SIZE - 6)
|
||
db 0ddh
|
||
endif
|
||
|
||
endm
|
||
|
||
stack_top label word
|
||
stack_ip dw ? ; Initial Offset
|
||
stack_cs dw ? ; Initial Code Segment (Unknown)
|
||
stack_flags dw ? ; Initial Flags (Unknown)
|
||
STACK ENDS
|
||
|
||
ED_TEXT SEGMENT
|
||
;
|
||
; Return the CheckSum of All the C code and Static Data. DS:SI
|
||
; are initialised to point at the C_code_start. AX contains the
|
||
; CheckSum on return.
|
||
;
|
||
calc_crc:
|
||
mov cx,real_code ; Number of bytes to move is always
|
||
shr cx,1 ; even because of the segment def.
|
||
dec cx
|
||
mov bx,0EDCh ; Checksum Seed
|
||
cc_10: ; Sum the words of the image while
|
||
lodsw ; rotating the check value
|
||
add bx,ax
|
||
rol bx,1
|
||
loop cc_10
|
||
xchg ax,bx
|
||
ret
|
||
|
||
page
|
||
;
|
||
; Return the code segment of the C main routine.
|
||
;
|
||
get_cs:
|
||
mov ax,cs:code_seg
|
||
ret
|
||
|
||
;
|
||
; Return the Data segment of the C data area
|
||
;
|
||
get_ds:
|
||
mov ax,cs:data_seg
|
||
ret
|
||
|
||
|
||
; Get remaining memory size, subtract code size and allocate high memory for
|
||
; transient portion of command processor
|
||
; Exit AX=Segment of high memory
|
||
; CY set if none available
|
||
;
|
||
; This used to allocate only just enough space for the code at the top of
|
||
; memory and leave the reset free for use as copy buffers.
|
||
; But then came SideKick Plus - this assumes COMMAND.COM only uses the top
|
||
; 20K of it's hi-mem partion and overwrites the rest as it gets it's
|
||
; overlays. As we are bigger the 20K the result is the system crashes when
|
||
; you exit back to the command line.
|
||
; In order to minimise this possibility we reserve some space (currently 50K)
|
||
; for use as copy buffers and allocate all the rest to the hi-mem portion
|
||
; of COMMAND.COM. Since SK starts overwriting from the bottom of memory it
|
||
; doesn't usually reach the code.
|
||
; The real solution is of course to make sure we are smaller than 20K too...
|
||
; (Or transfer the ReadLine code into the resident portion and checksum the
|
||
; hi-mem before returning to the hi-mem code ???).
|
||
; --ij
|
||
|
||
public alloc_com_memory
|
||
alloc_com_memory:
|
||
push es
|
||
mov bx,0FFFFh ; Allocate more paras than there are
|
||
mov ah,MS_M_ALLOC ; to find out how many there are.
|
||
int DOS_INT
|
||
mov ah,MS_M_ALLOC
|
||
int DOS_INT ; allocate it
|
||
|
||
mov si,code_length ; then convert the CODE_LENGTH to
|
||
mov cl,4 ; paragraphs and check if enough memory
|
||
shr si,cl ; is available to copy the code high
|
||
add si,1 ; + para for a memory descriptor
|
||
sub bx,si ; Is there enough for the code ?
|
||
jc acm_10 ; if not exit with error
|
||
|
||
|
||
cmp bx,Copy_Buffer_Size ; allocate some memory for Copy Buffers
|
||
jb acm_5
|
||
mov bx,Copy_Buffer_Size ; limit the maximum Copy Buffer size
|
||
acm_5:
|
||
mov es,ax
|
||
mov ah,MS_M_SETBLOCK
|
||
int DOS_INT ; shrink to fit
|
||
push es ; save buffer address
|
||
|
||
; Now allocate remaining memory for step aside code
|
||
mov bx,0FFFFh ; allocate all memory
|
||
mov ah,MS_M_ALLOC ; to find out how much there is.
|
||
int DOS_INT
|
||
mov ah,MS_M_ALLOC ; block at the end of memory
|
||
int DOS_INT ; AX=Segment of new block of memory
|
||
mov alloc_seg,ax ; save address so we can free it
|
||
if ThreeCOM
|
||
cmp bx,1000h ; do we have at least 64k ?
|
||
jb acm_6 ; if so do 3-Com fix and start
|
||
mov si,1000h ; Transient portion 64k down
|
||
acm_6:
|
||
endif
|
||
add ax,bx ; go to top of memory we allocated
|
||
|
||
cmp ax,0a000h ; dont use memory above A000 as this
|
||
jb acm_6a ; may disappear when user does
|
||
mov ax,0a000h ; MEMMAX -V
|
||
acm_6a:
|
||
|
||
dec si
|
||
sub ax,si ; adjust address we run cmd proc at
|
||
; Deallocate intervening block of memory
|
||
pop es
|
||
push ax
|
||
mov ah,MS_M_FREE ; Now free it up
|
||
int DOS_INT
|
||
pop ax
|
||
mov cs:_gp_far_buff,real_code
|
||
mov cs:_gp_far_buff+2,ax ; save address of temp buffer
|
||
clc ; allocated OK
|
||
acm_10:
|
||
pop es
|
||
ret
|
||
|
||
; called to free up the cmd processor's high memory
|
||
free_com_memory:
|
||
|
||
push es
|
||
push ax
|
||
mov es,alloc_seg
|
||
mov ah,MS_M_FREE
|
||
int DOS_INT
|
||
pop ax
|
||
pop es
|
||
ret
|
||
|
||
|
||
;Control_Break:
|
||
; The Break handler makes the following checks taking the
|
||
; appropriate action after each test:-
|
||
;
|
||
; 1) Is COMMAND.COM the current process (Get PSP) if NO ABORT
|
||
; 2) Is the break_flag SET if YES jump to the C break handler
|
||
; "break_handler" after insuring that the segment registers
|
||
; have all be set correctly.
|
||
;
|
||
assume cs:DGROUP, ds:nothing, es:nothing
|
||
|
||
; Set up the default Control Break Handler.
|
||
handler_init:
|
||
ifndef DOSPLUS
|
||
mov ax,4453h ; Get the address of the
|
||
int DOS_INT ; internal Critical Error
|
||
jc handler_i10 ; handler Ignore on Error
|
||
mov word ptr critical+0,ax ; Save the handler Offset (AX)
|
||
mov word ptr critical+2,bx ; and Segment (BX)
|
||
endif
|
||
mov al,24h ; Set the default Critical
|
||
mov dx,dataOFFSET critical_error ; Error Handler
|
||
mov bx,dataOFFSET crit_error_entry
|
||
call set_vector ; Setup correct ISR
|
||
|
||
handler_i10:
|
||
mov al,23h ; Set the default Control
|
||
mov dx,dataOFFSET control_break ; Break Handler
|
||
mov bx,dataOFFSET control_break_entry
|
||
;; jmp set_vector ; Setup correct ISR
|
||
;
|
||
; Convert the address of the interrupt #AL service routine, whose
|
||
; address is CS:DX to be PSP:xxxx. Five NOP must be coded after the
|
||
; interrupt service routine for the JMPF instruction which corrects
|
||
; the code segment.
|
||
;
|
||
set_vector:
|
||
push ds
|
||
push es
|
||
mov es,[low_seg]
|
||
mov es:byte ptr 0[bx],0EAh ; JMPF opcode
|
||
mov es:word ptr 1[bx],dx ; Offset of Interrupt vector
|
||
mov es:word ptr 3[bx],cs ; Insert the correct code seg
|
||
mov dx,bx
|
||
mov bx,es
|
||
sub bx,__psp ; Calculate the correct offset for
|
||
mov cl,4 ; the interrupt handler if the segment
|
||
shl bx,cl ; must be that of our PSP
|
||
add dx,bx
|
||
mov ds,__psp
|
||
mov ah,MS_S_SETINT
|
||
int DOS_INT
|
||
pop es
|
||
pop ds
|
||
ret
|
||
|
||
;extrn _int_break:near ; C Break/Error handling routine
|
||
|
||
assume cs:DGROUP, ds:DGROUP, es:nothing
|
||
|
||
control_break PROC FAR
|
||
;;db 5 dup(90h) ; Reserve space for JMPF CS:$+5
|
||
push ax ; Save the Users registers
|
||
push bx
|
||
push ds
|
||
call get_ds ; Get our Local DS
|
||
mov ds,ax
|
||
cmp _cbreak_ok,0 ; is our handler initialised ?
|
||
je break_05 ; no, don't call it
|
||
cmp reload_flag,0 ; Are we part way through reloading
|
||
clc ; the command processor?
|
||
jnz break_05 ; if so do not abort.
|
||
|
||
mov ah, MS_P_GETPSP ; Get the current PSP address
|
||
int DOS_INT
|
||
cmp bx,[__psp] ; Is this our address
|
||
stc ; Assume not and Set the carry flag
|
||
jz break_10 ; if internal, restart the command loop
|
||
; if external, abort process
|
||
break_05:
|
||
pop ds
|
||
pop bx
|
||
pop ax
|
||
ret
|
||
|
||
;
|
||
; This section of code corrects the stack and jumps to the
|
||
; C code Control Break Handler _int_break. Beware that the
|
||
; stack segment need not be the DS because the READ_LINE routine
|
||
; executes on a high stack and the CED programs will emulates
|
||
; a Control-Break on the wrong Stack.
|
||
;
|
||
break_10:
|
||
cli ; Swap to the correct stack not
|
||
mov ax,ds ; forgetting that we might be running
|
||
mov es,ax ; on old 8088 or 8086 so interrupts
|
||
mov ss,ax ; must be disabled
|
||
mov sp,stack_min ; Get the lowest possible stack address
|
||
add sp,12 ; Add a little to avoid problems with
|
||
sti ; the stack check code.
|
||
|
||
mov ax,0100h ; Termination Code Control-C Abort
|
||
push ax ; Save on the Stack for C routine
|
||
push ax ; Force a dummy return address on the
|
||
; stack (NOT USED)
|
||
call get_cs ; Put the Segment and Offset address
|
||
push ax ; of the C break Handler on the stack
|
||
mov ax,codeOFFSET _int_break; and execute a RETF to it.
|
||
push ax
|
||
ret
|
||
control_break ENDP
|
||
|
||
critical_error PROC FAR
|
||
;;db 5 dup(90h) ; Reserve space for JMPF CS:$+5
|
||
push ds ; Save the Critical Error DS
|
||
push ax
|
||
call get_ds ; Get the Command Processor DS
|
||
mov ds,ax ; and call the original routine
|
||
ifdef DOSPLUS
|
||
mov ax, _n_option ; check for /n command line option
|
||
cmp ax, 0
|
||
pop ax
|
||
jne skip_criterr
|
||
call com_criterr ; local criterr handler
|
||
jmp criterr_cont
|
||
skip_criterr:
|
||
mov al,3 ; /n option => always return fail
|
||
criterr_cont:
|
||
else
|
||
pop ax
|
||
pushf
|
||
call critical ; stored previous handler
|
||
endif
|
||
cmp al,02h ; Did the user request a Terminate
|
||
jne critical_e20 ; Yes so check if they are trying to
|
||
push ax ; terminate the command processor
|
||
push bx
|
||
|
||
mov ah, MS_P_GETPSP ; Get the current PSP address
|
||
int DOS_INT
|
||
cmp bx,[__psp] ; Is this our address?
|
||
jne critical_e10 ; no so return with Abort code
|
||
|
||
cmp in_exec,0 ; are we EXECing a program ?
|
||
jne critical_e10 ; then return the error
|
||
cmp reload_flag,0 ; then unless we are reloading command
|
||
je break_10 ; processor break here to prevent
|
||
critical_e10: ; higher levels generating repeated
|
||
pop bx ; critical errors (eg. when searching
|
||
pop ax ; a path)
|
||
critical_e20:
|
||
pop ds
|
||
iret
|
||
|
||
critical_error ENDP
|
||
|
||
;
|
||
; INT2E is a backdoor entry to the "Permanent" Command interpreter
|
||
; which will execute the command at DS:SI.
|
||
;
|
||
|
||
int2E_far_entry proc far
|
||
db 5 dup(90h) ; Reserve space for JMPF CS:$+5
|
||
|
||
; ds:si -> command line preceded by byte count
|
||
|
||
; check we're not re-entering
|
||
|
||
mov ax, 1
|
||
xchg cs:i2e_lock, ax
|
||
test ax, ax
|
||
jz i2e_10
|
||
|
||
iret
|
||
|
||
i2e_10:
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push si
|
||
push di
|
||
push bp
|
||
push ds
|
||
push es
|
||
|
||
; if ds = si = 0 then set batch_seg_ptr to zero and get out.
|
||
; This is a clean way of halting batch processing.
|
||
mov ax,ds
|
||
cmp ax,0
|
||
jne i2e_15
|
||
cmp si,0
|
||
jne i2e_15
|
||
|
||
mov si,cs:_batch_seg_ptr
|
||
mov ds,cs:_batch_seg_ptr+2
|
||
mov [si],ax
|
||
jmp i2e_exit2
|
||
i2e_15:
|
||
|
||
; swap stack
|
||
|
||
mov cs:i2e_user_ss, ss
|
||
mov cs:i2e_user_sp, sp
|
||
|
||
cli
|
||
mov ss, cs:exec_ss
|
||
mov sp, cs:exec_sp
|
||
sti
|
||
|
||
; allocate 128 bytes for command line, since the C code needs a 128
|
||
; byte buffer anyway
|
||
|
||
mov cx, 128
|
||
|
||
; save stack p
|
||
|
||
mov cs:i2e_stack, sp
|
||
|
||
; have we got enough room for command line
|
||
|
||
mov ax, sp
|
||
sub ax, cx
|
||
sub ax, cs:heap_top
|
||
cmp ax, 256
|
||
jge i2e_25
|
||
jmp i2e_exit
|
||
i2e_25:
|
||
sub sp, cx
|
||
mov cs:i2e_cmd, sp
|
||
|
||
; copy command line
|
||
|
||
push ss
|
||
pop es
|
||
mov di, sp
|
||
lodsb ; get line count
|
||
and ax,7fh ; limit to 128 bytes
|
||
add ax,sp ; terminating NULL goes here
|
||
rep movsb ; copy the command line
|
||
xchg ax,di ; DI -> NUL posn
|
||
xor al,al
|
||
stosb ; replace CR with NUL
|
||
push cs
|
||
pop ds
|
||
|
||
; reload non-resident code if necessary
|
||
|
||
cmp high_code, TRUE
|
||
jnz i2e_30
|
||
mov reload_flag, 1
|
||
call reload_code
|
||
mov reload_flag, 0
|
||
|
||
i2e_30:
|
||
; install our own Break and Criterr handlers - e.g. if second copy
|
||
; of the command processor is running, install original handlers so
|
||
; that they are looking at the same data as we are.
|
||
; N.B. __psp is currently that of original command processor
|
||
|
||
mov ax, (MS_S_GETINT*256) + 23h
|
||
int DOS_INT
|
||
mov i2e_i23seg, es
|
||
mov i2e_i23off, bx
|
||
|
||
mov ax, (MS_S_GETINT*256) + 24h
|
||
int DOS_INT
|
||
mov i2e_i24seg, es
|
||
mov i2e_i24off, bx
|
||
|
||
call handler_init
|
||
|
||
; save the command processor's __psp variable, and then set it to the
|
||
; psp of the process that called us. This is so that the Break and
|
||
; Criterr abort code can correctly determine whether the int2e command
|
||
; was internal or external
|
||
|
||
mov ah, MS_P_GETPSP
|
||
int DOS_INT
|
||
push bx ; save calling process's psp - EJH
|
||
mov bx, [__psp]
|
||
|
||
; Set current PSP to our own - EJH
|
||
mov ah, MS_P_SETPSP
|
||
int DOS_INT
|
||
|
||
; call C code
|
||
|
||
mov ax, code_seg
|
||
mov i2e_c_seg, ax
|
||
|
||
push i2e_cmd
|
||
call i2e_c_entry
|
||
pop ax ; clean up stack
|
||
|
||
; Set current psp back to that of calling process - EJH
|
||
pop bx
|
||
mov ah, MS_P_SETPSP
|
||
int DOS_INT
|
||
|
||
|
||
; restore interrupt vecs
|
||
|
||
push ds
|
||
lds dx, i2e_i23vec
|
||
mov ax, (MS_S_SETINT*256) + 23h
|
||
int DOS_INT
|
||
|
||
lds dx, cs:i2e_i24vec
|
||
mov ax, (MS_S_SETINT*256) + 24h
|
||
int DOS_INT
|
||
pop ds
|
||
|
||
cmp high_code, TRUE ; If not a .EXE then free
|
||
jnz i2e_ret ; any memory alocated by
|
||
call free_com_memory ; the Command Processor
|
||
i2e_ret:
|
||
|
||
i2e_exit:
|
||
; swap back the stack
|
||
|
||
cli
|
||
mov ss, i2e_user_ss
|
||
mov sp, i2e_user_sp
|
||
sti
|
||
|
||
i2e_exit2:
|
||
pop es
|
||
pop ds
|
||
pop bp
|
||
pop di
|
||
pop si
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
|
||
sub ax, ax
|
||
|
||
mov cs:i2e_lock, 0
|
||
ret 2
|
||
|
||
int2E_far_entry endp
|
||
|
||
|
||
_TEXT SEGMENT
|
||
assume cs:CGROUP, ds:DGROUP, es:nothing, ss:nothing
|
||
public _exec ; EXEC routine
|
||
|
||
;
|
||
; WORD CDECL exec(BYTE *path, UWORD type, BYTE *line, BOOLEAN back);
|
||
;
|
||
; back 10[bp]
|
||
; line 08[bp]
|
||
; type 06[bp]
|
||
; path 04[bp]
|
||
;
|
||
_exec:
|
||
;-----
|
||
push bp
|
||
mov bp,sp
|
||
push si
|
||
push di
|
||
push ds
|
||
push es
|
||
inc in_exec
|
||
cmp in_exec,1
|
||
je _exec10 ; Menuing system
|
||
push exec_ss ; save old stack_save if we
|
||
push exec_sp ; are being re-entered
|
||
_exec10:
|
||
mov si,08[bp] ; the Command Line
|
||
mov exec_env,0000
|
||
mov exec_clineoff,si
|
||
mov exec_clineseg,ds
|
||
mov exec_fcb1seg,ds
|
||
mov exec_fcb2seg,ds
|
||
|
||
push ds
|
||
pop es
|
||
;
|
||
; Extract two valid filenames from the CR terminated
|
||
; string passed in DS:SI. The FCBs will be generated in FCB1 and FCB2.
|
||
;
|
||
inc si
|
||
mov di,dataOFFSET fcb1 ; Blank fill the first FCB
|
||
call zap_fcb
|
||
call make_fcb ; Build first FCB
|
||
|
||
mov di,dataOFFSET fcb2 ; Blank fill the Second FCB
|
||
call zap_fcb
|
||
call make_fcb ; Build second FCB
|
||
|
||
mov ax,cs
|
||
jmp exec ; do FAR jmp to msdos_exec as we can't
|
||
_exec_ret: ; trust the stack when CALLing
|
||
dec in_exec ; Has PCTOOLS un-installed itself ?
|
||
jz _exec20 ; No so the stack contents are valid
|
||
js _exec_bad ; Yes, so exit by Ctrl-Break
|
||
pop exec_sp ; old stack save back again
|
||
pop exec_ss ; in the case of re-entry
|
||
_exec20:
|
||
|
||
pop es
|
||
pop ds
|
||
pop di
|
||
pop si
|
||
pop bp
|
||
mov ax,return_code
|
||
neg ax
|
||
ret
|
||
;
|
||
; We have returned from the EXEC function un-expectedly (because
|
||
; of PCTOOLS De-installation ?). Therefore the contents of the stack
|
||
; are invalid and we generate a Control-Break.
|
||
;
|
||
_exec_bad:
|
||
mov ax,0100h ; Termination Code Control-C Abort
|
||
push ax ; Save on the Stack for C routine
|
||
push ax ; Force a dummy return address on stack
|
||
mov in_exec,al ; zero in_exec count for next time
|
||
|
||
extrn _int_break:near ; C Break/Error handling routine
|
||
jmp _int_break ; now treat as ctrl-break
|
||
|
||
;
|
||
; Initialise the FCB entry a DX:DI and copy the Drive, FileName
|
||
; and extension form DS:SI when SI != 0FFFFh
|
||
;
|
||
zap_fcb:
|
||
mov ax,2000h ; Zero Fill first byte and last 4
|
||
stosb ; Drive code 0
|
||
xchg al,ah
|
||
mov cx,11 ; FileName and Ext to ' '
|
||
rep stosb
|
||
xchg al,ah
|
||
mov cl,4 ; Last four bytes to 00
|
||
rep stosb
|
||
sub di,16
|
||
ret
|
||
|
||
make_fcb:
|
||
call scan_filechar ; Get the Next File Character
|
||
push si
|
||
push di
|
||
push ax ; Save Character and Pointers
|
||
|
||
mov ax,(MS_F_PARSE shl 8) + 1 ; Parse the command line
|
||
int DOS_INT
|
||
|
||
pop ax
|
||
pop di ; Restore the Character and Pointer
|
||
|
||
cmp ah,'/' ; Was the arg preceeded by a '/'
|
||
jne make_fcb10 ; If it was roll back the cmd line
|
||
pop si ; pointer and blank all but the 1st
|
||
inc si ; char in the FCB
|
||
|
||
add di,2 ; Such that /FRED gives an FCB of 'F'
|
||
mov cx,10 ; and si points to the 'R'
|
||
mov al,' '
|
||
rep stosb
|
||
ret
|
||
|
||
make_fcb10:
|
||
pop ax ; discard original SI, skip name
|
||
jmp scan_sepchar ; skip until separator
|
||
|
||
;
|
||
; SCAN_SEPCHAR will search through the command line DS:SI
|
||
; which contains CX characters and return with SI pointing
|
||
; to the next SEPARATOR character.
|
||
;
|
||
; On Entry: DS:SI Character String
|
||
;
|
||
; On Exit: DS:SI First Non Separator
|
||
;
|
||
scan_sepchar:
|
||
push di ; Save DI ES points at this segment
|
||
mov ah,0 ; Invalidate Separator Character
|
||
|
||
scan_s10:
|
||
mov al,[si] ; Get the Character to Test
|
||
cmp al,CR
|
||
jz scan_s20 ; Have we reached the end of the string
|
||
mov cx,legal_length ; Scan the table of legal
|
||
mov di,dataOFFSET legal_table ; separators
|
||
repnz scasb ; Scan the List
|
||
jz scan_s20 ; Separator Located
|
||
inc si ; the character pointer
|
||
jmp SHORT scan_s10
|
||
|
||
scan_s20:
|
||
pop di
|
||
ret
|
||
;
|
||
; SCAN_FILECHAR will search through the command line DS:SI
|
||
; and return with SI pointing to the next NON_SEPARATOR character.
|
||
;
|
||
; On Entry: DS:SI Character String
|
||
;
|
||
; On Exit: DS:SI First Non Separator
|
||
; AH Last Valid Separator
|
||
;
|
||
scan_filechar:
|
||
push di ; Save DI ES points at this segment
|
||
mov ah,0 ; Invalidate Separator Character
|
||
scan_f10:
|
||
mov al,[si] ; Get the Character to Test
|
||
cmp al,CR
|
||
jz scan_f20 ; Have we reached the end of the string
|
||
mov cx,legal_length ; Scan the table of legal
|
||
mov di,dataOFFSET legal_table ; separators
|
||
repnz scasb ; Scan the List
|
||
jnz scan_f20 ; Non Separator Located
|
||
mov ah,al ; Save the Separator and increment
|
||
inc si ; the character pointer
|
||
jmp SHORT scan_f10
|
||
|
||
scan_f20:
|
||
pop di
|
||
ret
|
||
|
||
_TEXT ENDS
|
||
|
||
legal_table db ':.;,=+',9,' /<>|',22h,'[]'
|
||
legal_length equ 15
|
||
|
||
assume cs:DGROUP, ds:DGROUP, es:nothing, ss:nothing
|
||
|
||
public msdos_exec ; so it shows in map file
|
||
|
||
msdos_exec PROC FAR
|
||
push ax
|
||
cmp high_code,TRUE ; Check if the Command Processor Code
|
||
jnz msdos_e10 ; has been relocated to high memory
|
||
|
||
call free_com_memory ; free cmd processor memory
|
||
|
||
msdos_e10:
|
||
pop ax
|
||
mov bx,dataOFFSET exec_block
|
||
mov dx,04[bp] ; Get the Full Command Name
|
||
mov exec_ss,ss ; Save SS:SP in case somebody (NOVELL)
|
||
mov exec_sp,sp ; corrupts them
|
||
|
||
; The following 2 JMPF are kludged so that the INT22 vector saved in
|
||
; the child's PSP has the segment of the comand processors PSP.
|
||
; This is vital for many TSR management utilities.
|
||
;
|
||
|
||
; swap stack to conventional memory
|
||
cli ;
|
||
mov ax,__psp ;
|
||
mov ss,ax ;
|
||
mov sp,0100h ;
|
||
sti ;
|
||
|
||
db 0EAh ; JMPF Opcode
|
||
dw dataOFFSET psp_dofunc4b ; Corrected Offset
|
||
exec_psp dw 0 ; PSP Segment
|
||
|
||
assume cs:DGROUP, ds:nothing, es:nothing, ss:nothing
|
||
func4b_return:
|
||
mov ss,exec_ss ; Restore the real SS:SP
|
||
mov sp,exec_sp ; Using a CS overide
|
||
jc msdos_e20 ; if no error
|
||
xor ax,ax ; then zero return code
|
||
jmp msdos_e21
|
||
msdos_e20:
|
||
mov ah,59h ; get extended error code
|
||
sub bx,bx
|
||
int 21h
|
||
msdos_e21:
|
||
mov return_code,ax
|
||
call get_ds ; Point DS & ES to CSdata
|
||
mov ds,ax
|
||
mov es,ax
|
||
assume cs:DGROUP, ds:DGROUP, es:nothing, ss:nothing
|
||
|
||
call handler_init ; Re-initialise Control-Break and
|
||
; Critical error handlers for Novell
|
||
cmp high_code,TRUE ; Is the Command Code in High
|
||
jnz msdos_e30 ; memory ?
|
||
mov reload_flag,1 ; Reloading Command Processor
|
||
call reload_code ; Reload Command Processor Code
|
||
mov reload_flag,0 ; Command Processor Loaded
|
||
msdos_e30:
|
||
mov ax,code_seg ; Update the CS for the high code
|
||
mov msdos_exec_ret_seg,ax ; in case it has moved and return
|
||
jmp msdos_exec_ret
|
||
|
||
msdos_exec ENDP
|
||
|
||
_TEXT SEGMENT
|
||
assume cs:CGROUP, ds:DGROUP, es:nothing, ss:nothing
|
||
|
||
Public _readline
|
||
|
||
_readline:
|
||
;---------
|
||
cld
|
||
push bp
|
||
mov bp,sp
|
||
push si
|
||
push di
|
||
push es
|
||
ifdef DOSPLUS
|
||
mov ax,4456h ; Swap to the Command process
|
||
mov dl,1 ; History Buffer in DR DOS
|
||
int DOS_INT
|
||
else
|
||
push ds
|
||
call get_history_buffers ; get history buffers
|
||
mov P_SB_SEG[bx],ax ; swap to command one
|
||
pop ds
|
||
endif
|
||
mov ax,5d09h
|
||
int DOS_INT ; close remote spool files
|
||
mov ax,5d08h
|
||
mov dl,1
|
||
int DOS_INT ; Set truncate flag with redirected I/O
|
||
|
||
mov ah,MS_P_GETPSP ; get the current PSP
|
||
int DOS_INT ; then compare the STDERR entry in the
|
||
mov es,bx ; XFT with the Magic Number for CON
|
||
cmp es:byte ptr [18h+STDERR],1
|
||
mov dx,4[bp] ; get the buffer address and current
|
||
mov ax,cs ; AX = transient code segment
|
||
call readline ; do far call to msdos_readline
|
||
ifdef DOSPLUS
|
||
mov ax,4456h ; Swap to the Application process
|
||
mov dl,0 ; History Buffer in DR DOS
|
||
int DOS_INT
|
||
else
|
||
push ds
|
||
call get_history_buffers ; get history buffers
|
||
mov P_SB_SEG[bx],dx ; swap to application one
|
||
pop ds
|
||
endif
|
||
pop es
|
||
pop di
|
||
pop si
|
||
pop bp
|
||
ret
|
||
|
||
ifdef CDOS
|
||
get_history_buffers proc near
|
||
; On Entry:
|
||
; None
|
||
; On Exit:
|
||
; AX = command history buffers
|
||
; DX = application history buffers
|
||
; DS:BX -> pd
|
||
; NB. both DS and ES are corrupted by this call
|
||
;
|
||
mov ds,_sysdat_seg ; DS points to SYSDAT and ES to the
|
||
mov bx,ds:word ptr [68h] ; current process's UDA
|
||
mov dl,P_CNS[bx] ; DL = console number
|
||
mov es,P_UDA[bx]
|
||
push bx
|
||
mov ax,XIOS_HISTBUF ; Get the History Buffer Address's
|
||
call XIOS_ENTRY ; by calling ths XIOS
|
||
pop bx
|
||
ret
|
||
get_history_buffers endp
|
||
endif
|
||
|
||
_TEXT ENDS
|
||
|
||
assume cs:DGROUP, ds:DGROUP, es:nothing
|
||
|
||
;
|
||
; msdos_readline(BYTE *buffer);
|
||
;
|
||
; On Entry:
|
||
; flags - ZF set if we need to do Sidekick Plus check
|
||
; DS:DX -> buffer
|
||
; AX:0 -> Resident Section
|
||
; buffer
|
||
;
|
||
; The memory allocation for the hi-mem part of command.com has already been
|
||
; altered to minimise the chances of SideKick Plus overwriting the code.
|
||
; But it still can happen, say either on a machine with limited memory or
|
||
; other TSR's also loaded. In order to cater for this case we move the actual
|
||
; readline call into the resident portion and checksum things before returning
|
||
; to high memory - thus we can reload command.com if it get overwritten.
|
||
;
|
||
msdos_readline PROC FAR
|
||
pushf ; save the result for later
|
||
|
||
mov bx,sp ; SP before swapping stacks.
|
||
cli ; to RLSTACK
|
||
mov ss,ax ; above the Code and Messages
|
||
mov sp,codeOFFSET rlstack
|
||
sti
|
||
|
||
push bx ; save old SP
|
||
push ds
|
||
|
||
sub sp,260 ; make room for buffer on stack
|
||
mov di,sp ; save the address
|
||
|
||
push ds
|
||
push dx ; save real BUFFER for later...
|
||
push di ; and buffer on stack
|
||
|
||
mov si,dx ; point DS:SI at real buffer
|
||
mov dx,di ; point DX at stack buffer
|
||
push ss ; now get all the seg regs
|
||
pop es ; pointing to himem
|
||
mov cx,256/2
|
||
rep movsw ; copy resident buffer to stack
|
||
push ss ; DS:DX is stack buffer
|
||
pop ds
|
||
|
||
mov ax,4810h ; give DOSKEY a chance
|
||
int 2Fh
|
||
or ax,ax ; zero means DOSKEY has done it
|
||
jz msdos_rl10
|
||
|
||
mov word ptr [di],21cdh ; poke INT 21 and
|
||
mov byte ptr 2[di],0cbh ; RETF instruction
|
||
push cs ; save an address for the
|
||
mov ax,dataOFFSET msdos_rl10; RETF to return to
|
||
push ax
|
||
|
||
mov ah, MS_C_READSTR ; parameter for INT 21 readline
|
||
|
||
push ds ; finally jump to the INT 21
|
||
push di ; we have poked
|
||
ret
|
||
|
||
msdos_rl10:
|
||
pop si ; source is readline buffer
|
||
pop di ; recover old address
|
||
pop es ; and seg of real buffer
|
||
|
||
mov cl,ds:byte ptr [si] ; get MAX length
|
||
xor ch,ch ; make it a word
|
||
cld
|
||
rep movsb ; copy the string
|
||
|
||
add sp,260 ; recover my readline buffer space
|
||
pop ds
|
||
pop bx ; recover old SP
|
||
|
||
cli ; Now restore the normal C stack
|
||
call get_ds ; which is at DS:BX.
|
||
mov ss,ax
|
||
mov sp,bx
|
||
mov es,ax
|
||
sti
|
||
|
||
popf ; recover result of STDERR test
|
||
jne msdos_r10 ; if not CON, then skip the check
|
||
cmp high_code,TRUE ; Is the Command Code in High
|
||
jnz msdos_r10 ; memory ?
|
||
mov reload_flag,1 ; Reloading Command Processor
|
||
call reload_code ; Reload Command Processor Code
|
||
mov reload_flag,0 ; Command Processor Loaded
|
||
msdos_r10:
|
||
mov ax,code_seg ; Update the CS for the high code
|
||
mov word ptr -08[bp],ax ; in case it has moved and return
|
||
ret
|
||
msdos_readline ENDP
|
||
|
||
; Cmd processor is in high memory so check it out
|
||
reload_code:
|
||
cmp in_exec,1 ; If we landed here from an undefined area
|
||
je alloc_mem ; then free cmd processor memory
|
||
call free_com_memory
|
||
|
||
alloc_mem:
|
||
call alloc_com_memory ; Allocate memory for the Command
|
||
jc alloc_mem_error ; processor code.
|
||
push ax
|
||
call check_crc ; see if code has been trashed
|
||
pop ax
|
||
je still_there
|
||
mov code_seg,ax
|
||
jmp load_com ; Read in command Processor Code
|
||
|
||
still_there:
|
||
cmp ax,code_seg ; has the memory configuration changed?
|
||
je hasnt_moved ; (it will during Novell remote boot)
|
||
|
||
push ds
|
||
push es
|
||
|
||
mov cx,real_code
|
||
mov es,ax ; move the code to the new location
|
||
mov ds,code_seg ;
|
||
sub si,si ; ds:si -> old location
|
||
sub di,di ; es:di -> new location
|
||
|
||
rep movsb ; do it
|
||
|
||
mov cs:code_seg,es ; update code_seg with new location
|
||
|
||
pop es
|
||
pop ds
|
||
|
||
call check_crc ; recalculate the crc
|
||
jne load_com ; if its not valid we need to load
|
||
; from disk
|
||
|
||
hasnt_moved:
|
||
ret
|
||
|
||
alloc_mem_error:
|
||
; We can't reload COMMAND.COM because we haven't any memory
|
||
ifdef DLS
|
||
mov dx,_reload_msgm
|
||
else
|
||
mov dx,dataOFFSET _reload_msgm
|
||
endif
|
||
call reload_err ; say we can't reload COMMAND.COM
|
||
jmp $ ; stop forever....
|
||
|
||
check_crc:
|
||
; return with ZF set if himem crc's correctly
|
||
push ds
|
||
mov ds,code_seg
|
||
mov si,2
|
||
call calc_crc
|
||
pop ds ; Compare this crc with the one we got earlier
|
||
cmp crc,ax
|
||
ret
|
||
|
||
; If checksum is wrong load a new copy into high memory and patch new RET addr
|
||
|
||
open_err:
|
||
ifdef DLS
|
||
mov dx,_reload_msgf
|
||
else
|
||
mov dx,dataOFFSET _reload_msgf
|
||
endif
|
||
call reload_err ; prompt for COMMAND.COM
|
||
mov ah,MS_C_RAWIN ; Wait for the User to Press
|
||
int DOS_INT ; a key
|
||
|
||
load_com:
|
||
push ds
|
||
mov ds,[low_seg]
|
||
mov dx,dataOFFSET reload_file
|
||
mov ax,(MS_X_OPEN*256)+40h ; Try to open COMMAND.COM
|
||
int DOS_INT ; al=40h means NONE DENIED share mode
|
||
pop ds
|
||
jc open_err
|
||
mov bx,ax
|
||
|
||
xor dx,dx ; Take account of EXE header
|
||
cmp exe_file,FALSE ; if we were loaded as an EXE
|
||
je load_com_10
|
||
add dx,200h ; Assume header is 200h bytes
|
||
|
||
load_com_10:
|
||
xor cx,cx ; Now read the command processor code
|
||
add dx,total_length ; Seek to area of COMMAND.COM
|
||
mov ax,(MS_X_LSEEK*256)+0 ; containing code
|
||
int DOS_INT
|
||
jc read_err
|
||
|
||
push ds
|
||
mov cx,real_code
|
||
mov ds,code_seg ; DS:DX - > High memory area
|
||
xor dx,dx
|
||
mov ah,MS_X_READ ; Read the code into memory
|
||
int DOS_INT
|
||
|
||
pop ds
|
||
read_err:
|
||
mov ah,MS_X_CLOSE ; Close the file
|
||
int DOS_INT
|
||
|
||
call check_crc ; try and see if we loaded OK
|
||
jne open_err ; if not complain and try again
|
||
|
||
ret
|
||
|
||
reload_err:
|
||
; On Entry:
|
||
; DX = offset of final part of error message
|
||
;
|
||
push dx ; save final part of message
|
||
mov bx,STDERR ; Display on standard Error
|
||
ifdef DLS
|
||
mov dx,_reload_msgs
|
||
else
|
||
mov dx,dataOFFSET _reload_msgs
|
||
endif
|
||
call reload_err10
|
||
|
||
push ds
|
||
mov ds,[low_seg]
|
||
mov dx,dataOFFSET reload_file ; Filename
|
||
call reload_err10
|
||
pop ds
|
||
|
||
pop dx ; recover msg offset
|
||
;
|
||
; Calculate the length of the message to be displayed and output using
|
||
; MS_X_WRITE.
|
||
;
|
||
; DS:DX String to Output
|
||
; BX Output Handle
|
||
;
|
||
reload_err10:
|
||
xor al,al ; String Terminator
|
||
push es
|
||
push ds ; look for terminating BYTE
|
||
pop es ; in string at DS:DX
|
||
mov di,dx ; and get length to display
|
||
mov cx,0ffffh
|
||
repnz scasb ; look for terminator
|
||
not cx ; see how far we had to look
|
||
dec cx ; forget about the terminator
|
||
mov ah,MS_X_WRITE
|
||
int DOS_INT
|
||
pop es
|
||
ret
|
||
|
||
ED_TEXT ENDS
|
||
endif
|
||
|
||
page
|
||
_TEXT SEGMENT
|
||
assume cs:CGROUP, ds:DGROUP, ss:DGROUP
|
||
ifdef CDOSTMP
|
||
RSP_start:
|
||
mov ax,ds
|
||
mov es,ax
|
||
cli ; Swap stacks with interrupts disabled
|
||
mov ss,ax ; just in case we're on an 8088/86
|
||
mov sp,dataOFFSET stack_top
|
||
sti
|
||
mov insys,0 ; Reset the INSYS Flag
|
||
|
||
mov _gp_far_buff,dataOFFSET temp_buffer
|
||
mov _gp_far_buff+2,ax ; save address of temp buffer
|
||
|
||
mov dl,defconsole ; Set this process's Default Console
|
||
bdos C_SET
|
||
bdos C_ATTACH
|
||
|
||
bdos P_PDADR ; Get the address of the current
|
||
mov sysdat,es ; PD and SYSDAT
|
||
|
||
mov dl,BOOTDRV ; Get the BOOT Drive
|
||
mov es:P_DSK[bx],dl ; Update the running process
|
||
mov bx,dataOFFSET pd_seg ; Update the default drive field
|
||
mov P_DSK[bx],dl ; In the P_CREATE process descriptor
|
||
|
||
mov bx,es:INT17_PTR ; Initialise the default printer
|
||
mov al,defconsole ; from the INT17 Mapping Array
|
||
mul es:byte ptr [bx]
|
||
add bx,ax
|
||
mov dl,es:1[bx]
|
||
bdos L_SET
|
||
|
||
mov bx,es:INT14_PTR ; Initialise the default printer
|
||
mov al,defconsole ; from the INT14 Mapping Array
|
||
mul es:byte ptr [bx]
|
||
add bx,ax
|
||
mov dl,es:1[bx]
|
||
bdos A_SET
|
||
|
||
mov [code_seg],cs ; Update the CODE_SEG and EXEC_SEG
|
||
mov [exec_seg],ds ; variables
|
||
|
||
mov dl,0FFh ; Set the BDOS Error Mode to Return
|
||
bdos F_ERRMODE ; with No Display
|
||
|
||
mov dx,ds ; Initialise the DMA Segment
|
||
bdos F_DMASEG ; Pointer to Our DS
|
||
|
||
bdos P_PDADR ; Set ES:BX to the Process Descriptor
|
||
mov word ptr _pd,bx ; Save these values locally
|
||
mov word ptr _pd+2,es
|
||
mov _sysdat_seg,es
|
||
|
||
or es:P_CONMODE[bx],PCM_FCTLC
|
||
mov es:P_PARENT[bx],0 ; Zero the Parent Pointer
|
||
mov ax,es:P_UDA[bx] ; Finally get our UDA and save it.
|
||
mov uda,ax
|
||
|
||
|
||
mov ax,es:P_PSP[bx]
|
||
mov [__psp],ax
|
||
|
||
mov ax,XIOS_HISTBUF ; Get the History Buffer Address's
|
||
mov dl,defconsole ; for console number
|
||
call xios
|
||
mov cmd_histbuf,ax ; AX == Command Level History Buffer
|
||
mov prog_histbuf,dx ; DX == Program History Buffer
|
||
|
||
les bx,_pd ; Get the Process descriptor address
|
||
mov es:P_SB_SEG[bx],ax ; and use the Command Line
|
||
; History Buffer
|
||
|
||
; File Ownership stuff
|
||
les bx,_pd ; Get our process descriptor address
|
||
mov al,es:P_CNS[bx] ; get the current VC No.
|
||
xor ah,ah
|
||
mov bx,CCBLIST ; XIOS CCB$LIST
|
||
add bx,ax
|
||
add bx,ax
|
||
mov bx,es:word ptr [bx] ; extract the correct
|
||
mov ah,CCB_PCNS[bx] ; Physical Console Number.
|
||
|
||
mov ch,0
|
||
mov cl,NVCNS ; now work through all consoles
|
||
mov bx,CCBLIST ; looking for 1st one with this PC
|
||
RSP_start10:
|
||
mov di,es:word ptr [bx] ; Get the CCB address
|
||
cmp ah,CCB_PCNS[di] ; Is this the same physical console
|
||
je RSP_start20 ; no, ignore this one
|
||
add bx,2 ; onto next CCB
|
||
loop RSP_start10
|
||
jmp RSP_start60 ; impossible....
|
||
|
||
RSP_start20:
|
||
cmp al,CCB_VCNS[di] ; is it the same virtual console ?
|
||
je RSP_start40 ; yes, allocate new FA_ structure
|
||
RSP_start30:
|
||
push di
|
||
mov dx,5
|
||
bdos P_DELAY ; wait a bit
|
||
pop di ; then see if it has been allocated
|
||
mov si,CCB_OWNER[di] ; si -> owning process
|
||
mov si,es:P_FILE_ACCESS[si] ; File Access structure
|
||
test es:FA_FLAGS[si],FAF_TMP_INIT ; is it the new one ?
|
||
jz RSP_start30 ; no, delay again
|
||
inc es:FA_COUNT[si] ; one more user for this structure
|
||
les bx,_pd
|
||
xchg si,es:P_FILE_ACCESS[bx] ; replace existing one
|
||
dec es:FA_COUNT[si] ; one less user for old one
|
||
jmp RSP_start60
|
||
|
||
RSP_start40:
|
||
push ax ; save PC/VC
|
||
cmp ah,0 ; is it the main box ?
|
||
je RSP_start45
|
||
mov dx,5*50 ; delay PC Terminals 5 secs while
|
||
bdos P_DELAY ; main box starts up
|
||
RSP_start45:
|
||
mov DX,FA_LENGTH ; we need this much SYSDAT memory
|
||
bdos S_MEMORY ; for our file access structure
|
||
pop dx ; recover PC/VC
|
||
cmp ax,0FFFFh ; if no memory
|
||
je RSP_start50 ; then just keep root one
|
||
les di,_pd ; replace file access structure
|
||
xchg ax,es:P_FILE_ACCESS[di]
|
||
xchg ax,di
|
||
dec es:FA_COUNT[di] ; we have stopped using this structure
|
||
mov es:FA_USER[bx],0 ; user # is super user
|
||
mov es:FA_GROUP[bx],0 ; and group is super group
|
||
mov es:FA_DEF_ACCESS[bx],0 ; initialise the new structure
|
||
mov es:FA_COUNT[bx],1
|
||
RSP_start50:
|
||
les bx,_pd
|
||
mov bx,es:P_FILE_ACCESS[bx]
|
||
mov es:FA_FLAGS[bx],FAF_TMP_INIT
|
||
RSP_start60:
|
||
; File Ownership stuff ends
|
||
|
||
push ds
|
||
mov es,sysdat ; Get SYSDAT
|
||
mov dx,VERSION ; get OS label offset in SUP segment
|
||
mov ds,CCPMSEG ; get SUP segment for signon string
|
||
bdos C_WRITESTR ; print OS label on current console
|
||
pop ds
|
||
endif
|
||
;
|
||
;
|
||
assume cs:CGROUP, ds:DGROUP, es:DGROUP
|
||
;
|
||
; zero data areas (_BSS and c_common)
|
||
;
|
||
memory_init:
|
||
push ss
|
||
pop es
|
||
|
||
cld ; set direction flag (up)
|
||
mov di,dataOFFSET _edata ; beginning of bss area
|
||
mov cx,dataOFFSET _end ; end of bss area
|
||
sub cx,di
|
||
xor ax,ax
|
||
rep stosb ; zero bss
|
||
|
||
; C segmentation conventions set up here (DS=SS and CLD)
|
||
|
||
push ss ; set up initial DS=ES=SS, CLD
|
||
pop ds
|
||
assume ds:DGROUP
|
||
|
||
; do necessary initialization BEFORE command line processing !
|
||
|
||
ifndef CDOSTMP
|
||
push es
|
||
mov ax,4458h ; We now have an IOCTL function
|
||
int 21h ; to get our private data
|
||
jc mem_init10
|
||
ifdef DOSPLUS
|
||
;les ax,DRDOS_PD
|
||
;les ax,es:dword ptr 0000h[bx]
|
||
;mov word ptr _pd,ax
|
||
;mov word ptr _pd+2,es
|
||
;mov _sysdat_seg,es
|
||
else
|
||
mov es:byte ptr [bx],-1 ; say COMSPEC is loaded
|
||
mov cl,P_PDADR ; Set ES:BX to the Process Descriptor
|
||
mov ax,4459h ; use Int 21h so we don't crash if
|
||
int 21h ; under DOS and we will give an error
|
||
mov word ptr _pd,bx ; from COM.C init().
|
||
mov word ptr _pd+2,es ; Save these values locally
|
||
mov _sysdat_seg,es
|
||
endif
|
||
mem_init10:
|
||
pop es
|
||
endif
|
||
xor bp,bp ; mark top stack frame for SYMDEB
|
||
|
||
ifdef CDOSTMP
|
||
mov ax,dataOFFSET cmdline ; Pass a pointer to a NULL string
|
||
else
|
||
call get_cmdline ; Copy the command line to a local
|
||
endif
|
||
push ax ; buffer and pass the address to MAIN
|
||
call C_code_entry ; main ( cmd )
|
||
add sp,2 ; Restore the Stack
|
||
mov ah,MS_X_EXIT ; use whatever is in ax after
|
||
int DOS_INT ; returning here from main
|
||
|
||
page
|
||
;
|
||
; For TURBOC and METAWARE C the majority of the Command Processor
|
||
; messages are linked with the CGROUP in the MSG segment. When the
|
||
; compiler generates DGROUP relative references large offsets are
|
||
; produced. This occurs because the DGROUP is linked before the CGROUP
|
||
; and its MSG Segment. FARPTR converts a NEAR pointer into a FAR
|
||
; by checking the value of the offset against the DGROUP length.
|
||
; Offset greater than TOTAL_LENGTH must be in MSG so the pointer
|
||
; is converted to CS:x-TOTAL_LENGTH otherwise DS:x.
|
||
;
|
||
public _farptr
|
||
_farptr:
|
||
push bp
|
||
mov bp,sp
|
||
mov ax,04[bp]
|
||
mov dx,ds
|
||
cmp ax,total_length
|
||
jbe farptr_10
|
||
ifndef WATCOMC
|
||
sub ax,total_length
|
||
endif
|
||
mov dx,cs
|
||
farptr_10:
|
||
mov bx,dx
|
||
pop bp
|
||
ret
|
||
|
||
ifdef DLS
|
||
public _msgfarptr
|
||
_msgfarptr:
|
||
push bp
|
||
mov bp,sp
|
||
mov ax,04[bp]
|
||
add ax,offset CGROUP:_MSG
|
||
mov dx,cs
|
||
mov bx,dx
|
||
pop bp
|
||
ret
|
||
endif
|
||
|
||
; We need some additional support for the CMD_LIST - it contains near pointers
|
||
; to other items in the CGROUP. This routine turns a NEAR pointer into a FAR
|
||
; pointer.
|
||
public _cgroupptr
|
||
_cgroupptr:
|
||
push bp
|
||
mov bp,sp
|
||
mov ax,04[bp]
|
||
mov dx,cs
|
||
mov bx,dx
|
||
pop bp
|
||
ret
|
||
|
||
ifdef DLS
|
||
|
||
;/* Get the address of the msg_language variable in the DR BDOS. */
|
||
;GLOBAL BYTE FAR * CDECL get_msg_lang()
|
||
|
||
public _get_msg_lang
|
||
_get_msg_lang:
|
||
mov ax, 4458h ; IOCTL func: get ptr private data
|
||
int 21h ; pointer returned in ES:BX
|
||
jc _get_msg_lang_err ; skip if invalid function
|
||
add bx, 9 ; DLS version byte at offset 9
|
||
cmp es:byte ptr [bx], 1 ; correct version?
|
||
jne _get_msg_lang_err ; no - skip
|
||
inc bx ; DLS language byte at offset 10
|
||
mov ax,bx
|
||
mov dx,es ; return pointer in DX:AX
|
||
ret
|
||
|
||
_get_msg_lang_err:
|
||
mov ax,codeOFFSET dummy_lang
|
||
mov dx,cs
|
||
ret
|
||
|
||
dummy_lang db 0 ; default to primary language
|
||
|
||
endif
|
||
|
||
page
|
||
ifndef CDOSTMP
|
||
|
||
;
|
||
; This following routine copies the initial command line from the PSP
|
||
; into the CMDLINE data area. Processing any special switches and
|
||
; adding a terminating null character. The offset of the copy is
|
||
; returned in AX.
|
||
;
|
||
|
||
get_cmdline:
|
||
if 0
|
||
mov di,dataOFFSET cmdline
|
||
else
|
||
mov di,heap_top ; copy cmdline onto the heap
|
||
endif
|
||
push ds ; Preserve DS and point to PSP
|
||
mov ds,__psp ; Get the PSP address
|
||
xor cx,cx ; Now copy the command line
|
||
mov cl,ds:0080h ; Get the Command length
|
||
mov si,0081h ; and its start location
|
||
jcxz get_cmdl20
|
||
get_cmdl10:
|
||
lodsb ; Terminate the copy after
|
||
cmp al,0Dh ; CX bytes or earlier if a
|
||
jz get_cmdl20 ; CR or LF character is found.
|
||
cmp al,0Ah ; FrameWork Install Program and
|
||
jz get_cmdl20 ; Bitstream FontWare
|
||
stosb
|
||
loop get_cmdl10
|
||
|
||
get_cmdl20:
|
||
xor al,al ; Zero Terminate the command
|
||
stosb ; line copy for C.
|
||
pop ds
|
||
if 0
|
||
mov ax,dataOFFSET cmdline ; Return the command line
|
||
else
|
||
mov ax,di ; new bottom of heap
|
||
xchg ax,heap_top ; return old one = cmdline
|
||
endif
|
||
ret
|
||
|
||
;
|
||
; This routine will install the DS relative dummy INT 2E handler with
|
||
; a PSP:XXXX entry in the interrupt vector table. A JMPF is coded
|
||
; after the handler entry point inorder to correct CS.
|
||
;
|
||
Public _install_perm
|
||
_install_perm:
|
||
push es
|
||
mov ax,__psp ; Modify the INT 22 and 2E
|
||
mov es,ax ; vectors if the current process
|
||
cmp ax,PSP_PARENT ; is the ROOT DOS process. ie
|
||
jnz inst_p10 ; PSP_PARENT == PSP
|
||
|
||
mov al,2Eh ; Install the Command Processor
|
||
mov dx,dataOFFSET int2E_entry ; Backdoor entry
|
||
call inst_p30
|
||
|
||
mov al,22h ; Update the Command Processor
|
||
mov dx,dataOFFSET int22_entry ; Terminate address
|
||
call inst_p30
|
||
|
||
push ds ; When this is the ROOT process
|
||
push si ; then update the PSP copies of
|
||
push di ; interrupt vectors 22, 23, 24
|
||
push ds ; because some TSR management
|
||
pop es ; programs examine these variables
|
||
lea di,psp_save_area ; ES:DI -> save area for PSP
|
||
mov ds,__psp
|
||
lea si,PSP_TERM_IP ; DS:SI -> data in PSP to save
|
||
mov cx,6
|
||
rep movsw ; save the data for later EXIT
|
||
push ds
|
||
pop es
|
||
lea di,PSP_TERM_IP ; ES:DI -> PSP
|
||
mov ds,cx
|
||
mov si,022h * 4 ; DS:SI -> real interrupt vecs
|
||
mov cx,6
|
||
rep movsw
|
||
pop di
|
||
pop si
|
||
pop ds
|
||
|
||
inst_p10:
|
||
pop es
|
||
ret
|
||
|
||
inst_p30:
|
||
push ds
|
||
mov bx,[low_seg]
|
||
sub bx,__psp ; Calculate the correct offset for
|
||
mov cl,4 ; the interrupt handler if the segment
|
||
shl bx,cl ; must be that of our PSP
|
||
add dx,bx
|
||
mov ds,__psp
|
||
mov ah,MS_S_SETINT
|
||
int DOS_INT
|
||
pop ds
|
||
ret
|
||
|
||
page
|
||
;
|
||
; This routine will restore the Int 22 terminate address copy in
|
||
; the PSP in preperation for an EXIT (DeskView bug).
|
||
;
|
||
Public _restore_term_addr
|
||
_restore_term_addr:
|
||
push es
|
||
mov ax,__psp ; Restore the PSP we altered
|
||
mov es,ax ; if the current process
|
||
cmp ax,PSP_PARENT ; is the ROOT DOS process. ie
|
||
jne restore_ta10 ; PSP_PARENT == PSP
|
||
|
||
push si
|
||
push di
|
||
lea si,psp_save_area
|
||
lea di,PSP_TERM_IP
|
||
mov cx,6
|
||
rep movsw
|
||
pop di
|
||
pop si
|
||
|
||
restore_ta10:
|
||
pop es
|
||
ret
|
||
|
||
page
|
||
;
|
||
; This routine will restore the Novell error mode - BAP
|
||
;
|
||
Public _restore_error_mode
|
||
_restore_error_mode:
|
||
mov dl,net_error_mode
|
||
mov ah,0ddh ; set error mode to the value
|
||
int 21h ; it was when COMMAND was
|
||
ret ; executed
|
||
|
||
page
|
||
;
|
||
; MASTER_ENV will create a Master Environment of 04[bp] bytes unless
|
||
; the environment is already larger in which case the environment
|
||
; is increased by 128 bytes.
|
||
;
|
||
Public _master_env
|
||
_master_env:
|
||
push bp
|
||
mov bp,sp
|
||
push si
|
||
push di
|
||
push es
|
||
ifdef DOSPLUS
|
||
; mov ax,(MS_M_STRATEGY*256)+1
|
||
; mov bx,1 ; set memory strategy to best fit
|
||
; int DOS_INT
|
||
endif
|
||
mov bx,04[bp] ; Save the Specified Size
|
||
add bx,15 ; and force it to be an integer
|
||
and bx,not 15 ; multiple of 16
|
||
mov es,__psp ; Get the PSP Segment Address
|
||
|
||
mov cx,PSP_ENVIRON ; Get the environment segemnt
|
||
jcxz master_env10 ; Have we been loaded by DesQview ?
|
||
|
||
mov es,cx ; Scan through the environment and
|
||
xor di,di ; determine the Environment size and
|
||
xor ax,ax ; the Load file name
|
||
mov cx,7FFFh
|
||
|
||
master_env05:
|
||
repne scasb ; Scan for a ZERO byte
|
||
jcxz master_env10 ; Abort if maximum size exceeded
|
||
inc di ; Check if the next character was a 0
|
||
cmp al,es:-1[di] ; if YES then this is the end of the
|
||
jnz master_env05 ; environment
|
||
mov cx,di ; Calculate the environment Size
|
||
;
|
||
; CX contains the current environment size in bytes. 0 for a DesQview
|
||
; system or an empty environment.
|
||
;
|
||
master_env10:
|
||
cmp bx,cx ; Is the current environment larger
|
||
jae master_env15 ; No allocate requested value
|
||
mov bx,128
|
||
add bx,cx
|
||
|
||
master_env15:
|
||
push cx ; Save current Environment Size
|
||
mov cl,4 ; convert request to paragraphs
|
||
shr bx,cl
|
||
mov ah,MS_M_ALLOC ; Allocate Memory
|
||
int DOS_INT
|
||
pop cx
|
||
jc master_env30 ; Abort Memory Allocation Failed
|
||
|
||
mov es,__psp ; Copy the Environemt
|
||
xchg ax,PSP_ENVIRON ; Update the Environment Pointer
|
||
push ds
|
||
mov ds,ax ; DS -> Initial Environment
|
||
mov es,PSP_ENVIRON ; ES -> Master Environment
|
||
mov si,0
|
||
mov di,si
|
||
jcxz master_env20 ; If this was a Desqview exec then
|
||
rep movsb ; skip the environment copy and
|
||
; just initialize to 0000
|
||
|
||
if TRUE ; Invalidate the contents of the
|
||
not ds:word ptr 00h ; current environment so Novell
|
||
else ; Netware finds the correct Master
|
||
push es ; environment under Concurrent DOS.
|
||
mov es,ax ;
|
||
mov ah,MS_M_FREE ; A possible alternative is to free
|
||
int DOS_INT ; the old environment but this would
|
||
pop es ; change the memory allocations for
|
||
endif ; sub-sequent loads.
|
||
|
||
master_env20:
|
||
pop ds
|
||
xor ax,ax
|
||
stosw
|
||
|
||
master_env30:
|
||
ifdef DOSPLUS
|
||
; mov ax,(MS_M_STRATEGY*256)+1
|
||
; xor bx,bx ; set memory strategy to first fit
|
||
; int DOS_INT
|
||
endif
|
||
pop es
|
||
pop di
|
||
pop si
|
||
pop bp
|
||
ret
|
||
|
||
endif
|
||
page
|
||
ifndef DOSPLUS
|
||
;
|
||
; UWORD FAR *sysdat(WORD *);
|
||
;
|
||
Public _sysdat
|
||
_sysdat:
|
||
push bp
|
||
mov bp,sp
|
||
push es
|
||
BDOS S_SYSDAT ; Get the SYSDAT segment address
|
||
mov ax,word ptr 04[bp] ; and the SYSDAT byte offset
|
||
mov bx,es ; and return a FAR pointer to the
|
||
mov dx,bx ; data required. MSC uses DX:AX
|
||
pop es ; but cater for other compilers
|
||
pop bp ; just in case.
|
||
ret
|
||
endif
|
||
|
||
ifdef DOSPLUS
|
||
;
|
||
; BOOLEAN CDECL int10_cls();
|
||
;
|
||
; int10_cls will return TRUE if it issued an INT10 function to
|
||
; clear the screen.
|
||
;
|
||
Public _int10_cls
|
||
_int10_cls:
|
||
push bp
|
||
push si
|
||
push di
|
||
push es
|
||
mov ax,(MS_X_IOCTL*256)+0 ; Get the device attributes for
|
||
mov bx,STDOUT ; STDOUT
|
||
int DOS_INT
|
||
mov ax,0000 ; Assume that the test fails
|
||
jc int10_exit ; and return FALSE to the caller
|
||
and dl,092h ; Check that STDOUT is the Console
|
||
cmp dl,092h ; Out DEVICE and it supports INT29
|
||
jnz int10_exit ; Fast output
|
||
|
||
;;mov es,ax ; Now check that the INT29 routine
|
||
;;mov bx,es:word ptr (29h*4)+2; is below the INT20 service routine
|
||
;;cmp bx,es:word ptr (20h*4)+2; ie that this is a BIOS device driver
|
||
;; jae int10_exit ; No way Jose
|
||
; So what if it isn't?
|
||
|
||
mov ax,1A00h ; ANSI.SYS installation check
|
||
int 2Fh ; AL = FF on return if ANSI installed
|
||
cbw ; AX = FFFF if ANSI present
|
||
inc ax ; AX = 0 if ANSI present
|
||
jz int10_exit
|
||
|
||
|
||
; get number of lines
|
||
|
||
call cginfo ; get screen resolution
|
||
push dx ; screen lines
|
||
|
||
mov ah, 0fh ; get mode
|
||
int 10h
|
||
and al,7fh
|
||
mov ah, 0 ; set mode, clear screen (al bit 7 clear)
|
||
int 10h
|
||
|
||
call cginfo ; has resolution changed?
|
||
pop ax ; restore screen lines
|
||
|
||
cmp al, dl ; has # of screen lines changed?
|
||
je int10_done ; skip if still the same
|
||
|
||
mov ax, 1112h ; character generator
|
||
mov bl, 0 ; set 8x8 double dot font
|
||
int 10h
|
||
|
||
mov ax, 1103h ; set block specifier
|
||
mov bl, 0
|
||
int 10h
|
||
|
||
int10_done:
|
||
mov ax,1 ; All done
|
||
|
||
int10_exit:
|
||
pop es
|
||
pop di
|
||
pop si
|
||
pop bp
|
||
ret
|
||
|
||
cginfo:
|
||
mov dl, 24 ; assume default # for CGA/MDA
|
||
mov ax, 1130h ; character generator info
|
||
mov bh, 0
|
||
int 10h
|
||
ret ; dl = nlines - 1
|
||
|
||
endif
|
||
|
||
ifdef CDOSTMP
|
||
|
||
xios:
|
||
push ds ; Save the entry segment registers
|
||
push es ; then call the XIOS correctly with
|
||
; DS pointing to SYSDAT and ES to the
|
||
mov es,uda ; current process's UDA
|
||
mov ds,sysdat
|
||
call XIOS_ENTRY
|
||
pop es
|
||
pop ds
|
||
ret
|
||
|
||
endif
|
||
|
||
ifndef DOSPLUS
|
||
;
|
||
; _vc_data(&vc_base, &vc_num, &pc_num)
|
||
;
|
||
; VC_DATA returns the first Virtual Console attached to the current
|
||
; physical console, the number of virtual consoles attached and the
|
||
; physical console.
|
||
;
|
||
Public _vc_data
|
||
_vc_data:
|
||
push bp
|
||
mov bp,sp
|
||
push es
|
||
push si
|
||
push di
|
||
mov si,04[bp] ; SI == &VC_BASE
|
||
mov word ptr [si],0000 ; *vc_base = 0
|
||
|
||
les bx,_pd ; Get our process descriptor address
|
||
mov ah,0
|
||
mov al,NVCNS
|
||
mov cx,ax
|
||
mov al,es:P_CNS[bx] ; get the current VC No.
|
||
mov bx,CCBLIST ; XIOS CCB$LIST
|
||
mov di,ax ; Calculate the correct entry in
|
||
shl di,1 ; the CCB$LIST which points to our
|
||
mov di,es:word ptr [di+bx] ; CCB and then extract the correct
|
||
mov al,CCB_PCNS[di] ; Physical Console Number.
|
||
mov di,08[bp] ; Get the address of the PC_NUM
|
||
mov word ptr [di],ax ; and save the Physical Console Number
|
||
mov di,0000 ; From CCB 0
|
||
|
||
vc_d10:
|
||
push di
|
||
mov di,es:word ptr [di+bx] ; Get the CCB ad<61>ress
|
||
cmp al,CCB_PCNS[di] ; Is this theY$ame physical console
|
||
pop di ; Restore the original DI
|
||
jz vc_d30 ; Yes then save info
|
||
vc_d20:
|
||
inc word ptr [si] ; *VC_BASE++
|
||
inc di ; Point to the next entry in
|
||
inc di ; the CCB$LIST and try again
|
||
loop vc_d10
|
||
jmp vc_exit
|
||
|
||
vc_d30:
|
||
mov si,06[bp] ; VC_NUM
|
||
mov word ptr [si],0000 ; *VC_NUM = 0
|
||
vc_d40:
|
||
push di
|
||
mov di,es:word ptr [di+bx] ; Get the CCB address
|
||
cmp al,CCB_PCNS[di] ; Is this the same physical console
|
||
pop di ; Yes then increment the count
|
||
jnz vc_exit ; and continue.
|
||
inc word ptr [si] ; *VC_NUM++
|
||
inc di ; Point to the next entry in
|
||
inc di ; the CCB$LIST and try again
|
||
loop vc_d40
|
||
|
||
vc_exit:
|
||
pop di
|
||
pop si
|
||
pop es
|
||
pop bp
|
||
ret
|
||
endif
|
||
|
||
_TEXT ENDS
|
||
page
|
||
ifdef CDOSTMP
|
||
|
||
RSF_DYNAMIC equ 0001h ; create at boot time
|
||
RSF_NONBANK equ 0002h ; allocate non-banked
|
||
RSF_SPECIAL equ 0004h ; requires separate code
|
||
RSF_ENVIRON equ 0008h ; requires large environment
|
||
|
||
PD_SEG SEGMENT
|
||
;
|
||
; This is the standard process descriptor for a TMP. During
|
||
; the Concurrent P_CREATE function the contents of this process
|
||
; descriptor are copied to a full size descriptor inside SYSDAT.
|
||
;
|
||
dw 0,0 ; link fields
|
||
db PS_RUN ; status
|
||
db 200 ; priority
|
||
dw PF_SYS+PF_KEEP+PF_SPECIAL; flags
|
||
db 'Tmp ' ; Process Name
|
||
dw 40h/10h ; uda seg
|
||
db 0,0 ; disk,user
|
||
db 0,0 ; ldisk,luser
|
||
dw 0FFFFh ; mem (Shared Code)
|
||
dw 0,0 ; dvract,wait
|
||
db 0,0 ; org,net
|
||
dw 0 ; parent
|
||
cns db 0,0 ; cns,abort
|
||
db 0,0 ; cin,cout
|
||
db 0,0 ; lst,sf3
|
||
db 0,0 ; sf4,sf5
|
||
dw 0,0 ; reserved
|
||
dw 0,0 ; pret,scratch
|
||
PD_SEG ENDS
|
||
|
||
UDA_SEG SEGMENT
|
||
uda_size dw ULEN,80h,0,0 ;0-7
|
||
dw 0,0,0,0 ;8-fh
|
||
dw 0,0,0,0 ;10-17
|
||
dw 0,0,0,0 ;18-1f
|
||
dw 0,0,0,0 ;20-27
|
||
dw 0,0,0,0 ;28-2f
|
||
dw 0,0 ;30-33
|
||
uda_SP dw dataOFFSET uda_stack,0 ;34-37
|
||
dw 0,0,0,0 ;38-3f
|
||
dw 0,0,0,0 ;40-47
|
||
dw 0,0,0,0 ;48-4f
|
||
uda_CS dw 0 ;50-51
|
||
uda_DS dw 0 ;52-53
|
||
uda_ES dw 0 ;54-55
|
||
uda_SS dw 0 ;56-57
|
||
dw 0,0,0,0 ;58-5f
|
||
insys db 1,0 ;60-61
|
||
dw 0,0,0 ;62-67
|
||
db (ULEN-6Eh)dup(0CCH) ; Initialise System Stack
|
||
uda_stack dw codeOFFSET RSP_start ; Initial Offset
|
||
dw ? ; Initial Segment (Unknown)
|
||
dw ? ; Initial Flags (Unknown)
|
||
UDA_SEG ENDS
|
||
|
||
endif
|
||
|
||
ifdef DOSPLUS
|
||
_TEXT SEGMENT
|
||
public _show_help
|
||
public _put_resident_high
|
||
public _get_config_env
|
||
public _get_original_envsize ; BAP added this
|
||
|
||
_show_help PROC NEAR
|
||
;
|
||
; VOID show_help(index)
|
||
; WORD index
|
||
;
|
||
;out 0fdh,al
|
||
|
||
push bp
|
||
mov bp,sp
|
||
sub sp,4 ; require 2 WORD local variables
|
||
|
||
mov ah,MS_M_ALLOC ; allocate memory for the help text
|
||
mov bx,help_length ; bx = no. paragraphs
|
||
mov cl,4
|
||
shr bx,cl
|
||
int DOS_INT ; do it
|
||
jnc show_help_05
|
||
jmp show_help_err0 ; exit on error
|
||
show_help_05:
|
||
mov -2[bp],ax ; save segment of allocated memory
|
||
|
||
push ds
|
||
mov ds,[low_seg]
|
||
mov dx,dataOFFSET reload_file
|
||
mov ax,(MS_X_OPEN*256)+0 ; Open the COMMAND.COM file
|
||
int DOS_INT ; do it
|
||
pop ds
|
||
jc show_help_err1 ; exit on error
|
||
mov bx,ax ; bx = file handle
|
||
mov -4[bp],ax ; save handle for later
|
||
|
||
xor cx,cx
|
||
xor dx,dx
|
||
cmp exe_file,TRUE ; if command.com is an EXE file take
|
||
jne show_help_10 ; account of the EXE header
|
||
add dx,200h
|
||
show_help_10:
|
||
add dx,total_length
|
||
add dx,cgroup_length
|
||
add dx,cend_length ; dx = file offset of help text
|
||
mov ax,(MS_X_LSEEK*256)+0 ; seek to the right location
|
||
int DOS_INT ; do it
|
||
jc show_help_err2 ; exit on error
|
||
|
||
push ds
|
||
mov ds,-2[bp] ; ds = help text segment
|
||
xor dx,dx ; dx = 0;
|
||
mov ah,MS_X_READ ; read from COMMAND.COM file
|
||
mov cx,help_length ; cx = no. bytes required
|
||
int DOS_INT ; do it
|
||
pop ds
|
||
jc show_help_err2 ; exit on error
|
||
cmp ax,0 ; zero bytes read means there's no
|
||
je show_help_err2 ; help seg tagged to file.
|
||
|
||
ifdef DLS
|
||
call _get_msg_lang ; get a far pointer to msg_language var
|
||
mov es,dx ; dx:ax = far pointer on return
|
||
mov bx,ax ;
|
||
mov bx,es:[bx] ; bx = msg_language
|
||
shl bx,1 ; multiply bx by 2
|
||
else
|
||
xor bx,bx ; bx = 0
|
||
endif
|
||
mov es,-2[bp] ; ds = help text segment
|
||
mov bx,es:[bx] ; bx -> help message offset table
|
||
mov ax,4[bp] ; ax = message index
|
||
shl ax,1 ; multiply by 2
|
||
add bx,ax ; bx -> offset of required message
|
||
mov bx,es:[bx] ; bx -> message
|
||
|
||
call write_string ; display the message
|
||
|
||
show_help_err2:
|
||
mov ah,MS_X_CLOSE ; close the file
|
||
mov bx,-4[bp] ; bx = file handle
|
||
int DOS_INT ; do it
|
||
|
||
show_help_err1:
|
||
mov ah,MS_M_FREE ; free the memory
|
||
push es
|
||
mov es,-2[bp] ; es = segment to free
|
||
int DOS_INT ; do it
|
||
pop es
|
||
|
||
show_help_err0:
|
||
add sp,4
|
||
pop bp
|
||
ret
|
||
|
||
|
||
write_string:
|
||
;extrn _str:byte
|
||
|
||
; es -> help segment
|
||
; bx -> message in help segment
|
||
|
||
write_string_00:
|
||
;mov di,dataOFFSET _str ; di -> local buffer
|
||
mov di,[heap_top]
|
||
write_string_05:
|
||
mov al,es:[bx] ; get a character
|
||
cmp al,0ah ; check for NEWLINE...
|
||
jnz write_string_10 ; ...jump if its not
|
||
|
||
mov al,0dh ; replace LF with CR LF
|
||
mov [di],al ;
|
||
inc di ;
|
||
mov al,0ah ;
|
||
mov [di],al ;
|
||
inc di ;
|
||
mov al,0 ;
|
||
mov [di],al ; terminate string
|
||
call flush_buff ; display it
|
||
inc bx ;
|
||
jmp write_string_00 ; start again
|
||
|
||
write_string_10:
|
||
cmp al,0 ; check for NULL...
|
||
jnz write_string_20 ; ...jump if its not
|
||
|
||
mov [di],al ; store char
|
||
call flush_buff ; display string
|
||
jmp write_string_90 ; exit
|
||
|
||
write_string_20:
|
||
cmp al,'%' ; messages have doubled %'s because
|
||
jnz write_string_30 ; were intended for printf originally.
|
||
inc bx ; => skip next character.
|
||
write_string_30:
|
||
mov [di],al ; store char
|
||
inc di ;
|
||
inc bx ;
|
||
jmp write_string_05 ; loop
|
||
|
||
write_string_90:
|
||
ret
|
||
|
||
flush_buff:
|
||
extrn strlen_:near
|
||
extrn c_write_:near
|
||
|
||
;mov ax,dataOFFSET _str ; watcom C requites first param in AX
|
||
mov ax,[heap_top]
|
||
call strlen_ ; get length of string
|
||
mov dx,ax ; watcom C requires second param in DX
|
||
;mov ax,dataOFFSET _str ; watcom C requires first param in AX
|
||
mov ax,[heap_top]
|
||
call c_write_ ; display the string
|
||
ret
|
||
|
||
_show_help ENDP
|
||
|
||
|
||
|
||
try_high_memory PROC NEAR
|
||
; This function attempts to allocate some high memory at FFFF:E0 by modifying
|
||
; the HIMEM FREE CHAIN maintained by the BDOS.
|
||
; on entry: bx = no. paras required (preserved)
|
||
; on exit: Carry Set = unsuccessful
|
||
; otherwise
|
||
; ax = FFFF = segment of allocated memory
|
||
; HIMEM Free Chain is modified.
|
||
|
||
|
||
push ds
|
||
push es
|
||
push bx
|
||
|
||
mov cl,4 ; multiplying bx by 4...
|
||
shl bx,cl ; ...gives memory required in bytes
|
||
mov dx,bx ; put it in dx because bx is used for
|
||
; somthing else
|
||
|
||
|
||
add dx,HISEG_OFF
|
||
|
||
mov ax,4458h ; get private data area
|
||
int DOS_INT ; do it
|
||
mov si,es:10h[bx] ; ax = start of HIMEM Free Chain
|
||
test si,si ; zero means there's no chain so...
|
||
je thm_unsuccessful; ...return unsuccessful
|
||
|
||
mov ax,0FFFFh ;
|
||
mov ds,ax ; ds:si -> first free himem area
|
||
|
||
cmp si,HISEG_OFF ; check if area starts at or below HISEG_OFF
|
||
ja thm_unsuccessful; ...return unsuccessful
|
||
mov cx,2[si] ; CX = length of free area
|
||
cmp cx,dx ; check if length >= that required
|
||
jb thm_unsuccessful; ...return unsuccessful
|
||
|
||
mov ax,[si] ; assume we will use the entire block
|
||
mov es:10h[bx],ax ; so unlink it from the chain
|
||
|
||
mov di,HISEG_OFF ; generate HIMEM REGISTRATION link and
|
||
mov ax,di ; update root in private data area
|
||
xchg ax,es:14h[bx]
|
||
mov [di],ax
|
||
mov 2[di],dx ; remember how much we have used
|
||
|
||
; JBM commented this line out, I put it back in. (BAP)
|
||
sub 2[di],di
|
||
; see above comment (JBM)
|
||
|
||
sub cx,dx ; subtract amount used from actual size
|
||
cmp cx,256 ; if less than 256 bytes are left
|
||
jb thm_success ; then just forget about them
|
||
|
||
mov si,di ; there is enough to be worth recyling
|
||
add si,dx ; SI -> free block following allocation
|
||
mov 2[si],cx ; it's this long
|
||
mov ax,si
|
||
xchg ax,es:10h[bx] ; put at head of HMA free chain
|
||
mov [si],ax
|
||
thm_success:
|
||
mov ax,0ffffh ; return success
|
||
clc ;
|
||
jmp thm_exit ;
|
||
|
||
thm_unsuccessful:
|
||
stc ; return failure
|
||
thm_exit:
|
||
pop bx
|
||
pop es
|
||
pop ds
|
||
ret
|
||
|
||
try_high_memory ENDP
|
||
|
||
|
||
_put_resident_high PROC NEAR
|
||
;
|
||
; VOID put_resident_high(param)
|
||
; WORD param;
|
||
;
|
||
; param = 0 Try HIGH memory, then UPPER memory
|
||
; param = 1 Only try HIGH memory
|
||
; param = 2 Only try UPPER memory
|
||
;
|
||
|
||
PRH_PARAM equ word ptr 4[bp]
|
||
|
||
push bp
|
||
mov bp,sp
|
||
push si
|
||
push di
|
||
|
||
|
||
mov ax,(MS_M_STRATEGY*256)+2
|
||
int DOS_INT ; get existing HMA link
|
||
mov ah,0
|
||
push ax ; save it
|
||
mov bx,total_length ; get size of resident code/data
|
||
sub bx,(dataOFFSET hi_seg_start)-15
|
||
mov cl,4 ; subtract size of low memory stub
|
||
shr bx,cl ; bx = block size in paras.
|
||
|
||
cmp PRH_PARAM,2 ; skip the next bit if we're only
|
||
je prh_upper ; looking at UPPER memory
|
||
|
||
call try_high_memory ; first try to allocate high memory
|
||
; ie seg FFFF
|
||
jnc prh_success ; jump if successful
|
||
|
||
cmp PRH_PARAM,0 ; if we're only looking at HIGH memory
|
||
jne prh_exit ; then we exit now
|
||
|
||
prh_upper:
|
||
push bx ; save length
|
||
mov ax,(MS_M_STRATEGY*256)+1
|
||
mov bx,41h ; set memory strategy to best fit
|
||
int DOS_INT ; upper only
|
||
mov ax,(MS_M_STRATEGY*256)+3
|
||
mov bx,1 ; try to link in upper memory
|
||
int DOS_INT
|
||
pop bx ; recover length
|
||
jc prh_exit ; no upper memory, stop now
|
||
|
||
mov ah,MS_M_ALLOC ; allocate some memory
|
||
int DOS_INT ; do it
|
||
jc prh_exit ; no upper memory, stop now
|
||
|
||
sub ax,HISEG_OFF/16 ; bias segment appropriately
|
||
|
||
prh_success:
|
||
; AX = segment to relocate to
|
||
;
|
||
mov es,ax ; es = new block
|
||
|
||
mov si,dataOFFSET hi_seg_start ; start at R_TEXT segment
|
||
mov di,si
|
||
|
||
mov cx,total_length ; get size of resident code/data
|
||
sub cx,si ; subtract size of low memory stub
|
||
|
||
mov [reloc_seg],ax ; These values in the low memory
|
||
mov [reloc_off],di ; stub are used by TaskMAX to find
|
||
mov [reloc_size],cx ; the relocated code/data
|
||
|
||
|
||
mov [data_seg],ax ; update data_seg variable
|
||
mov [exec_seg],ax ; and some others...
|
||
mov [readline_seg],ax
|
||
mov [func4b_seg],ax
|
||
mov [int2E_seg],ax
|
||
mov ds:word ptr [control_break_entry+3],ax
|
||
mov ds:word ptr [crit_error_entry+3],ax
|
||
|
||
add si,4 ; take account of HIMEM
|
||
add di,4 ; REGISTRATION link
|
||
sub cx,4
|
||
|
||
rep movsb ; move'em
|
||
|
||
mov bx,ds
|
||
sub bx,[__psp] ; ax = difference between psp and data
|
||
add bx,HISEG_OFF/16 ; add size of bit we leave behind
|
||
|
||
mov es,[__psp] ; es -> old location
|
||
|
||
mov ds,ax ; this is the new data seg
|
||
mov ss,ax ; and also the new stack seg
|
||
|
||
mov ah,MS_M_SETBLOCK ; modify old segment size
|
||
int DOS_INT ; do it
|
||
|
||
prh_exit:
|
||
pop bx ; recover upper memory link
|
||
mov ax,(MS_M_STRATEGY*256)+3
|
||
int DOS_INT ; restore to original state
|
||
|
||
mov ax,(MS_M_STRATEGY*256)+1
|
||
xor bx,bx ; set memory strategy to first fit
|
||
int DOS_INT
|
||
|
||
|
||
pop di
|
||
pop si
|
||
pop bp
|
||
|
||
ret
|
||
|
||
_put_resident_high ENDP
|
||
|
||
|
||
_get_config_env PROC NEAR
|
||
|
||
; BYTE FAR *get_config_env();
|
||
; This function returns a pointer to the start of the config.sys
|
||
; environment.
|
||
|
||
mov ax,4458h ; get pointer to private data
|
||
int DOS_INT ; do it
|
||
mov ax,0 ; es:bx -> private data
|
||
jc get_cfg_env10
|
||
xchg ax,es:18[bx] ; ax = segment of config environment
|
||
get_cfg_env10:
|
||
mov bx,ax ; return FARNULL (0000:0000)
|
||
mov dx,ax
|
||
xor ax,ax
|
||
ret
|
||
|
||
_get_config_env ENDP
|
||
|
||
|
||
; BAP - This routine finds the orignal COMMAND.COM's environment size.
|
||
; This may not be the best way of doing it .. !
|
||
; It finds the PSP of the original COMMAND.COM by checking the PSP seg
|
||
; against the parent PSP seg. If they are not the same, it repeats for
|
||
; the parent. When they are the same, it has found the original COMMAND
|
||
; and finds the environment size.
|
||
|
||
_get_original_envsize PROC NEAR
|
||
push bp
|
||
mov bp,sp
|
||
push si
|
||
push di
|
||
push es
|
||
push cx
|
||
mov ah,51h
|
||
int DOS_INT ; get current PSP seg
|
||
try_next:
|
||
mov es,bx
|
||
mov cx,bx ; move into CX
|
||
mov bx,0
|
||
mov ax,es:16h[bx] ; get parent PSP seg in ax
|
||
cmp ax,cx ; are they the same ?
|
||
je got_org_psp ; yes - found COMMAND.COM PSP
|
||
mov bx,ax ; else make this current seg and
|
||
jmp try_next ; try again
|
||
|
||
got_org_psp:
|
||
mov es,ax ; ES = COMMAND.COM PSP seg
|
||
mov bx,0
|
||
mov ax,es:2ch[bx] ; get env seg in ax
|
||
cmp ax,0 ; seg = 0000 ?
|
||
je bomb_out ; yes - forget it
|
||
dec ax ; AX:0000 points to memory descriptor
|
||
mov es,ax
|
||
mov ax,es:3[bx] ; find length of seg ( in paras)
|
||
mov cl,4
|
||
shl ax,cl ; convert to bytes
|
||
bomb_out:
|
||
mov bx,ax
|
||
mov dx,ax
|
||
pop cx
|
||
pop es
|
||
pop di
|
||
pop si
|
||
pop bp
|
||
ret
|
||
_get_original_envsize ENDP
|
||
|
||
|
||
_TEXT ENDS
|
||
endif
|
||
|
||
ifndef CDOSTMP
|
||
|
||
R_TEXT SEGMENT
|
||
extrn _out_pipe:byte
|
||
extrn _kbdbuf:byte
|
||
R_TEXT ENDS
|
||
|
||
_TEXT SEGMENT
|
||
|
||
public _get_reload_file
|
||
_get_reload_file:
|
||
|
||
; copy reload_file to heap
|
||
|
||
push ds
|
||
push es
|
||
push si
|
||
push di
|
||
|
||
;mov ax,0e40h
|
||
;int 10h
|
||
|
||
mov ax,ds
|
||
mov es,ax
|
||
mov ds,[low_seg]
|
||
mov di,[heap_top]
|
||
mov si,offset reload_file
|
||
cld
|
||
grf_loop:
|
||
lodsb
|
||
stosb
|
||
cmp al,0
|
||
jnz grf_loop
|
||
|
||
pop di
|
||
pop si
|
||
pop es
|
||
pop ds
|
||
ret
|
||
|
||
public _set_reload_file
|
||
_set_reload_file:
|
||
|
||
; copy string on heap to reload file
|
||
|
||
push es
|
||
push si
|
||
push di
|
||
|
||
;mov ax,0e40h
|
||
;int 10h
|
||
|
||
mov es,[low_seg]
|
||
mov si,[heap_top]
|
||
mov di,offset reload_file
|
||
cld
|
||
srf_loop:
|
||
lodsb
|
||
stosb
|
||
|
||
cmp al,20h ; BAP from here
|
||
jne srf_brian ; if AL = 20h, poke a 00
|
||
xor al,al ; in instead, to terminate
|
||
dec di ; the file. COMSPEC can then have
|
||
stosb ; switches, but reload_file is
|
||
srf_brian: ; just the file name.
|
||
|
||
cmp al,0
|
||
jnz srf_loop
|
||
|
||
pop di
|
||
pop si
|
||
pop es
|
||
ret
|
||
|
||
public _get_out_pipe
|
||
_get_out_pipe:
|
||
|
||
; copy out_pipe filename from low_seg to data seg
|
||
|
||
push ds
|
||
push es
|
||
push si
|
||
push di
|
||
|
||
;mov ax,0e40h
|
||
;int 10h
|
||
|
||
mov ax,ds
|
||
mov es,ax
|
||
mov di,offset DGROUP:_out_pipe
|
||
|
||
mov ds,[low_seg]
|
||
mov si,offset out_pipe
|
||
|
||
mov cx,8
|
||
cld
|
||
rep movsb
|
||
|
||
pop di
|
||
pop si
|
||
pop es
|
||
pop ds
|
||
ret
|
||
|
||
public _docmd_int2f
|
||
;
|
||
; BOOLEAN docmd_int2f(BYTE *cmdline, BYTE *cmd, UWORD count);
|
||
;
|
||
; cmdline db max, actual, 'COMMAND LINE', CR
|
||
; cmd db length, 'COMMAND', CR
|
||
; count db remaining length of tail, FF/00 internal/external flag
|
||
;
|
||
;
|
||
|
||
_docmd_int2f:
|
||
|
||
push bp
|
||
mov bp,sp
|
||
push bx
|
||
push si
|
||
|
||
mov bx,4[bp] ; bx -> original command line
|
||
mov si,6[bp] ; si -> upper cased command
|
||
mov cx,8[bp]
|
||
mov dx,0ffffh
|
||
|
||
mov ax,0AE00h
|
||
int 2fh
|
||
|
||
test al,al
|
||
jz docmd_int2f_exit
|
||
|
||
mov bx,4[bp]
|
||
mov si,6[bp]
|
||
mov cx,8[bp]
|
||
mov dx,0ffffh
|
||
|
||
mov ax,0AE01h
|
||
int 2fh
|
||
mov al,1
|
||
docmd_int2f_exit:
|
||
cbw ; return true if handled
|
||
pop si
|
||
pop bx
|
||
pop bp
|
||
mov bx,ax
|
||
mov dx,ax
|
||
ret
|
||
|
||
_TEXT ENDS
|
||
|
||
endif
|
||
|
||
end ; start address
|