;-----------------------------------------------------------------------------
;
;		    (c) 1982 Knowledge Engineering, Inc.
;
; NAME
;
;	EXEC -- Execute .COM file passing parameters
;
; SYNOPSIS
;
;	exec(prog, parms);
;	char *prog;		pointer to the .COM file to load and execute
;	char *parms;		pointer to the parameter line to pass
;
; DESCRIPTION
;
;	Loads and transfers execution to the .COM file passed.  If the .COM
;	file is not found or invalid filename is passed, then control is
;	returned back to the calling program.
;
; CAUTIONS
;
;	This procedure can only be used with Lattice C or one that simulates
;	the calling structure, registers, etc. of Lattice C.
;
; CHANGES
;
;	5-06-83	jam	Fixed so loader portion relocates itself in high
;			memory versus high end of data segement.
;
;-----------------------------------------------------------------------------
;
;	Beginning of EXEC
;
	EXTRN	_TOP:WORD		;SS:_TOP is the top of memory
PGROUP	GROUP	PROG
PROG	SEGMENT	BYTE PUBLIC 'PROG'
	ASSUME	CS:PGROUP
;
;
;	Constants
;
BEGPROG EQU	100H			;Offset where prog is to be loaded
BLANK	EQU	20H			;Blank (space)
CMNDLN	EQU	81H			;Offset where command line begins
CTRLM	EQU	0DH			;Carriage return
DOS	EQU	21H			;DOS function call
EXT	EQU	09H			;Filename extension
FCB	EQU	5CH			;Location of FCB for prog to load
FCB2	EQU	6CH			;Location of 2nd FCB in Program Segment
LENFCB	EQU	25H			;Length of an FCB
LENFN	EQU	0BH			;Length of filenames
MAXCMND EQU	7EH			;Maximum # characters in command line
NULL	EQU	00H			;End-of-string character in C
NUMCHAR	EQU	80H			;Offset to length of command line
OPEN	EQU	0FH			;Open file
PARSE	EQU	29H			;Parse line for filename
PROGDTA	EQU	80H			;Loaded programs default DTA
RECLEN	EQU	0EH			;Record length part of FCB
RNDREAD EQU	27H			;Random block read
SETDTA	EQU	1AH			;Set Disk Transfer Address
sizseg	equ	10H			;Number of bytes per segment
sizmem	equ	02H			;Total amount of system memory
TOTMEM	EQU	06H			;Location of maximum size of segment
TWOFCB	EQU	1EH			;# bytes of two unopened FCB's
;
; Dynamic storage layout for EXEC
;
DYNS	STRUC
OLD_BP	DW	?			;Caller's BP save
RETN	DW	?			;Return address from call
PRGM	DW	?			;Ptr to name of COM file to execute
PARM	DW	?			;Ptr to paramater list
DYNS	ENDS
;
;
;-----------------------------------------------------------------------------
;
; NAME
;
;	LOADER -- loads and executes program requested
;
; SYNOPSIS
;
;	execute a long jump to relocated LOADER
;
; DESCRIPTION
;
;	This section of code is relocated into the top of memory by EXEC and
;	then executed.  When control is transferred:
;
;	     DS equals the code segment of where the program is to be loaded
;	     The top of the stack must have the length of the paramater line
;
;-----------------------------------------------------------------------------
;
;
;
LOADER:
;
;	Set additional parms
;
	MOV	SI,FCB			;Access opened FCB of program to load
	MOV	WORD PTR [SI+RECLEN],1	;Set record length to 1 (one) byte
	MOV	CX,WORD PTR DS:[TOTMEM] ;Get maximum size of segment
;
;	Set the Data Tarnsfer Area to the beginning of the calling program
;
	MOV	DX,BEGPROG
	MOV	AH,SETDTA
	INT	DOS			;Set DTA
;
;	Read the program into memory
;
	MOV	DX,FCB			;Set DX to opened FCB
	MOV	AH,RNDREAD
	INT	DOS			;Perform block read
	JCXZ	LDRERR			;Error if no records read
	CMP	AL,1			;Chk if EOF
	JNZ	LDRERR			;If not, error in reading
;
;	Set the two FCB's in the program segment to NULL FCB's
;
	MOV	AX,DS			;Set to the new CS
	MOV	ES,AX
	MOV	SI,FCB			;Set source
	MOV	BYTE PTR [SI],NULL
	MOV	DI,FCB+1		;Set destination
	MOV	CX,TWOFCB-1		;Set counter
	cld
	REP	MOVSB			;Null them out
;
;	Set the length of the command line
;
	POP	AX			;Get length that was set in EXEC
	MOV	SI,NUMCHAR
	MOV	BYTE PTR [SI],AL	;Set length
;
;	All segment registers must be the same
;
	MOV	AX,DS
	MOV	SS,AX
	MOV	SP,5CH			;Stack must be 5CH
;
;	Set the new DTA
;
	MOV	DX,PROGDTA
	MOV	AH,SETDTA
	INT	DOS
;
;	Jump to beginning of new program
;
	MOV	DX,BEGPROG		;Beginning of program
	XOR	AX,AX
	PUSH	AX			;Value of Flag register
	PUSH	DS			;New CS
	PUSH	DX			;Beginning of program
	IRET				;Jump to loaded program
;
;	Error in loading -- execute INT 20 in Program Segment Prefix
;
LDRERR: XOR	AX,AX
	PUSH	AX			;Value of Flag register
	PUSH	DS			;CS of Program Segment Prefix
	PUSH	AX			;Jump to INT 20 of Prog. Seg. Prefix
	IRET
sizldrs EQU	(($ - LOADER) / sizseg) + 1
sizldrb	equ	($ - LOADER)
;
;
;
	PUBLIC	EXEC
EXEC	PROC	NEAR
	PUSH	BP
	MOV	BP,SP
	PUSH	DS
	PUSH	ES
;
;	Reset FCB to all zero's
;
	PUSH	DS
	MOV	AX,CS			;Set source of FCB
	MOV	DS,AX
	MOV	SI,FCB
	MOV	BYTE PTR [SI],0
	MOV	ES,AX			;Set destination of FCB
	MOV	DI,FCB+1
	MOV	CX,LENFCB-1		;Set counter
	cld
	REP	MOVSB			;Blank it out
;
;	Parse program name and setup FCB
;
	POP	DS			;Restore DS
	MOV	DI,FCB
	MOV	SI,[BP].PRGM		;Set source to filename
	MOV	AL,1			;Scan off leading seperators
	MOV	AH,PARSE
	INT	DOS			;Parse program name
	CMP	AL,0			;Chk if bad filename, ext, or drive
	JG	EXECERR			;If so, return
	CMP	BYTE PTR ES:[DI+1],BLANK ;Chk for valid filename
	JE	EXECERR			;If not, return
;
;	Program to load must be a COM file
;
	MOV	AX,CS			;Point to unopened FCB
	MOV	DS,AX
	MOV	BYTE PTR [DI+EXT],'C'
	MOV	BYTE PTR [DI+EXT+1],'O'
	MOV	BYTE PTR [DI+EXT+2],'M'
;
;	Open program to load
;
	MOV	DX,FCB
	MOV	AH,OPEN
	INT	DOS			;Open file
	OR	AL,AL			;Chk for error
	JNZ	EXECERR			;If so, return
;
;	Copy parm line passed to unformatted parm area in Prog. Seg. Prefix
;
	PUSH	DS			;Save for later
	MOV	AX,SS			;Set source registers
	MOV	DS,AX
	MOV	SI,[BP].PARM
	MOV	DI,CMNDLN		;Set destination registers
NEXTCH: MOV	AL,[SI]			;Get next character
	MOV	CS:[DI],AL		;Copy character
	INC	SI
	INC	DI
	CMP	AL,NULL			;Chk for end-of-string
	JNE	NEXTCH			;If not, copy the next character
	SUB	DI,CMNDLN		;Calculate length of command line
	MOV	DX,DI			;Keep the length
	POP	DS			;Restore DS
;
;	Calculate new location of LOADER
;
	mov	di,cs:sizmem		;Get top of memory
	sub	di,sizldrs
	MOV	BX,DI			;Save for later
;
;	POINT OF NO RETURN -- from here on control can not be returned to the
;			      calling program
;
	mov	ax,cs
	mov	ss,ax			;Reset the Stack Pointer
	mov	sp,5CH
	PUSH	DX			;Save length of command line for LOADER
;
;	Relocate LOADER
;
	mov	es,bx			;Set destination registers
	mov	di,0
	MOV	SI,OFFSET LOADER
	mov	cx,sizldrb		;Move the size of LOADER
	cld
	REP	MOVSB			;Copy loader into data area
;
;	Set stack for interrupt return to LOADER
;
	XOR	AX,AX
	PUSH	AX			;Value of Flag register
	PUSH	ES			;CS of LOADER
	PUSH	AX			;Beginning of LOADER
	IRET				;Jump far to relocated LOADER
EXECERR:
	POP	ES			;Error occured, return to caller
	POP	DS
	POP	BP
	RET
EXEC	ENDP
PROG	ENDS
	END