	title	Runtime Overlay Loader User Module for Plink86
	subttl	Written by Dave Hirschman, Phoenix Software Associates, Ltd.
	.sfcond
		;******************************
		;* Overlay Loader User Module *
		;******************************
;    Users may modify this routine and link it into their programs to change the
;way the Plink86 overlay loader operates.  All messages generated at runtime,
;as well as any communications carried out with the operator, are handled here.
;This module also controls the process by which the linkage editor searches for
;the overlays.  Modifications should be made with care:  Phoenix will probably
;be unsympathetic to those who make changes and then expect us to help with the
;debugging.  However, virtually any modifications needed to make your
;application run more smoothly may be accomplished by making minor changes to
;this code.  Also, see the "SAMPLE.ASM" file for a much simpler version of
;this module.
;
;    As the program begins execution the $OVLYIU routine is called before
;the application code executes.  Initialization is performed here.  The DS
;register is set to enable local data to be accessed, but the ES register
;points to the MSDOS program segment prefix.  The standard user module uses
;this to obtain the address of the environment (specifically the PATH string).
;These strings are directory names used by the system to find executable files,
;and they are used in the same way here to find overlay files.
;
;    The overlay loader calls symbol $OVLYxU each time it is about to open a
;new overlay file (keep in mind that a file can contain several overlays), or
;whenever a fatal error is encountered while reading an overlay.  The name of
;the overlay file being requested is provided in a string area labled by public
;symbol $OVLYFN, and may be modified if desired.  The file name must be
;terminated by a NUL, and the string area must be at least 13 bytes
;long.  As initialized by the overlay loader, the file name consists of a
;name and type only, of maximum length 8 and 3 chars respectively, separated
;by a period.
;
;    A result code is provided in the AL register describing what happened
;during the previous attempt to load an current overlay from the current file:
;
;0 - The first attempt to load an overlay has not been made yet.
;1 - The overlay file was not found.
;2 - The overlay file couldn't be opened due to a disk error.  These errors
;    are things like no disk in drive, drive not ready, or media errors such
;    as seek and CRC problems.
;3 - The overlay couldn't be read completely (premature EOF).  The file
;    is probably smashed.
;4 - The overlay couldn't be read because of a disk error (drive not ready,
;    media error, etc).
;
;    After possibly making modifications to the overlay file name, the $OVLYxU
;routine must return, in the AL register, a function code instructing the
;overlay loader how to handle the next attempt to load the overlay:
;
;0 - Try to load the overlay from the file name given in $OVLYFN.
;1 - Give up.  The program is normally terminated when this code is received.
;    However, if the user program called the overlay loader itself (at the
;    $LOAD$ routine, see Plink86 user manual), an error code may be returned to
;    the user program at its option.
;
;    The standard routine shown here uses the sequence number to try various
;strategies in order.  First, the unmodified file name is tried.  Next, a
;default string is appended to the front of the given file name.  This string
;starts out as "A:".  Beginning with the third attempt file name prefixes are
;obtained from the MSDOS 2.0 PATH (if any).  After these have been exhausted
;subsequent attempts are handled the same as the second attempt, after giving
;the operator an opportunity to modify the default string.  The operator may
;also terminate the program at this point (code 1 is returned to the overlay
;loader).
;
	name	OVLYM
	public	$OVLYMU ;entry point for MSDOS user routine
	public	$OVLYIU	;entry point to initialize user module
	public	$OVLYFN	;overlay file name string
;
;********
;* Data *
;********
;
CR	equ	0DH
LF	equ	0AH
Sep	equ	'\'	;char to separate Msdos 2.0 directory names
;
OVdata	segment	word public 'OVERLAYLOADER'

MSdos2	db	0	;0=>msdos 1.1, else 2.0
EnvPar	dw	0	;paragraph address of environment
EnvOff	dw	0	;offset to PATH string
TryEnv	dw	0	;current offset to PATH string
Path	db	"PATH"	;environment name for executable files path string
Psize = 4		;length of Path

Method	db	0	;determines method to use to set overlay file name
Pflag	db	0	;1=>DspFN should display file name prefix w/ file name
FNlen	equ 80
$OVLYFN	db FNlen dup (?) ;overlay file name work area
KeyBuf	dw	66	;Buffer size for buffered keyboard input O.S. call.
Prefix	db	"A:"	;default prefix for file names
	db 64 dup (?)
;
;	All messages are here.
SignOn	db	CR,LF,"Gratzle Crogler - $"
AskPrf	db	".",CR,LF,"Enter file name prefix (X: or path name/) "
	db	"or '.' to quit=>$"
Err	db	"Fatal error - $"
Err1	db	"Can't find file $"
Err2	db	"Disk I/O error in $"
NewLin	db	CR,LF,"$"
OVdata	ends
;
;********
;* Code *
;********
;
OVcode	segment  public 'OVERLAYLOADER'
	assume cs:OVcode, ds:OVdata, es:OVdata
;
;*******
;* Sys *
;*******
;This is a macro for doing operating system calls.
;
LodOff	macro	Reg,Var		;;macro to load variable offset into register.
	mov	Reg,offset Var		;;MSDOS, offsets are from segment
	endm
;
Sys	macro	Fun,Arg		;;macro for invoking Operating system functions
	mov	AH,Fun
	ifnb	<Arg>
	LodOff	DX, Arg
	endif
	int	21H
	endm
;
;**********
;* GetEnv *
;**********
;    The environment paragraph address is given in the program prefix (pointed
;to by ES as the program begins execution) at offset 2CH.  The environment
;consists of strings separated by nuls, with an extra nul at the end.  Each
;string has a name at the front and a value at the end, separated by an equal
;sign.  The string searched for here has a name of "PATH".  The value portion
;of this string is a list of directory names separated by semi-colons.  The
;command processor looks in these directories to find executable files, so
;program overlays might also be found there.  If the "PATH" string is found,
;its address is saved for later use.
;
Space	proc	near		;scan until a non-blank is found.
	mov	AL," "
Space1:	scasb
	jz	Space1
	dec	DI
	ret
Space	endp
;
GetEnv	proc	near
	mov	AX,ES:2CH		;Save environment paragraph address.
	mov	EnvPar,AX
	mov	ES,AX			;set ES to environment
	xor	DI,DI			;DI is offset into it.
	cld				;auto-increment forward.
Srch:	test	byte ptr ES:[DI],-1	;end of environment?
	jz	E1		
	mov	SI,offset Path		;no, compare next string
	mov	CX,Psize
	repe cmpsb
	jz	GotIt
;
Skip:	xor	AL,AL			;get past string and nul terminating it
Skip1:	scasb
	jnz	Skip1
	jmp	Srch			;back to try next string.
;
GotIt:	call	Space
	cmp	byte ptr ES:[DI],'='	;at end of found string?
	jnz	Skip			;no.
	inc	DI			;yes, get over =.
	call	Space			;and spaces.
	mov	EnvOff,DI		;save pointer to it.
;
E1:	ret
GetEnv	endp
;
;***********
;* $OVLYIU *
;***********
;If we are running under MSDOS 2.0 the environment is searched for the PATH
;string.
;
$OVLYIU	proc	near
	Sys	30H		;running under MSDOS 2.0?
	mov	BL,0
	cmp	AL,2
	jc	Set2
	call	GetEnv		;yes, look for PATH
	mov	BL,-1
Set2:	mov	MSdos2,BL	;save 2.0 flag.
	ret
$OVLYIU	endp
;
;*********
;* DspFN *
;*********
;The current overlay file name is displayed.
;
DspFN	proc	near
	test	Pflag,-1	;want prefix printed?
	jz	DspFN1
	LodOff	SI,Prefix	;yes, SI points to it.
	call	near ptr DspFN2	;print it.
DspFN1:	LodOff	SI,$OVLYFN	;now print file name.
DspFN2:	mov	DL,[SI]		;display text from SI until NUL found.
	or	DL,DL
	jz	DspFN3
	push	SI
	Sys	2
	pop	SI
	inc	SI
	jmp	DspFN2
DspFN3:	ret
DspFN	endp
;
;**********
;* GetPrf *
;**********
;This routine is called to get a file name prefix from the operator.  If the
;operator complies, it is left in the Prefix buffer.  If the operator enters
;a period, routine returns with the carry flag set.
;
GetPrf	proc	near
	Sys	9,AskPrf		;get new prefix
	Sys	10,KeyBuf
	Sys	9,NewLin
	mov	AL,byte ptr Prefix	;terminate if period entered
	cmp	AL,'.'
	jz	GP4
	mov	BL,byte ptr KeyBuf+1	;AL = # chars read.
	xor	BH,BH
	mov	byte ptr Prefix[BX],0	;set last byte to NUL
	xor	SI,SI			;change all chars to upper case
GP1:	mov	AL, byte ptr Prefix[SI]
	test	AL,-1
	jz	GP3
	cmp	AL,'z'+1
	jnc	GP2
	cmp	AL,'a'
	jc	GP2
	and	AL,0DFH
	mov	byte ptr Prefix[SI],AL
GP2:	inc	SI
	jmp	GP1
GP3:	clc				;all ok.
	ret
GP4:	stc				;operator wants to quit.
	ret
GetPrf	endp
;
;**********
;* Append *
;**********
;The file name prefix pointed to by BP:SI is appended to the front of the file
;name string.  Much of the code here involves moving segment registers around,
;because the prefix may exist in a different segment if it is coming from the
;PATH in the environment area.  DX must contain any extra space needed at the
;end of the prefix.  At the end of this routine DI points to the char following
;the prefix in the file name area (i.e. 1st char of file name) and SI points to
;the end of the source prefix string.
;
Append	proc	near
	mov	BX,ES		;save current DS and ES in BX.
	mov	DS,BP
	push	SI
	dec	DX		;DX := length of file name prefix + extra.
Count:	lodsb
	inc	DX
	or	AL,AL
	jz	CntEnd
	cmp	AL,' '
	jz	CntEnd
	cmp	AL,';'
	jnz	Count
CntEnd:	LodOff	SI, $OVLYFN	;DS:SI -> end of file name
	mov	DS,BX
	push	SI		;ES:DI -> end of file name area
	add	SI,FNlen-1
	mov	DI,SI
	sub	SI,DX
	mov	CX,FNlen	;shift file name up by length of prefix.
	sub	CX,DX
	std
	rep movsb
	cld
;
	pop	DI		;move prefix to file name area.
	pop	SI
	mov	DS,BP
	mov	ES,BX
	mov	CX,DX
	rep movsb
;
	mov	DS,BX		;restore DS
	ret
Append	endp
;
;**********
;* SetPrf *
;**********
;The current file name prefix is appended to the front of the file name.
;
SetPrf	proc	near
	mov	BP,DS		;BP:SI points to prefix.	
	LodOff	SI, Prefix
	xor	DX,DX		;Don't need any extra
	jmp	Append
SetPrf	endp
;
;**********
;* TryPth *
;**********
;If MSDOS 2.0 is running, the file name prefix is set up as the next directory
;name from the PATH string in the environment, if any.
;
TryPth:	test	MSdos2,-1		;if running 2.0, 
	jz	NoPath
	mov	SI,TryEnv		;try next path
	or	SI,SI
	jz	NoPath
	push	DS			;DS:SI->next environment string
	mov	AX,EnvPar
	mov	DS,AX
;
Try1:	lodsb				;get to start of next directory path
	cmp	AL,';'
	jz	Try1
	cmp	AL,' '
	jz	Try1
	dec	SI
;
	test	byte ptr [SI],-1	;anything here?
	mov	BP,DS			;(BP -> prefix paragraph)
	pop	DS			;(restore DS)
	jz	NoPath
	mov	DX,1			;yes, append it to file name, saving	
	call	Append			;room to add separator.
;
	dec	SI			;save new ptr for next time.
	mov	TryEnv,SI
	dec	DI			;add separator to fn.
	mov	byte ptr [DI],Sep
	clc				;fn ready to use now.
	ret
;
NoPath:	stc
	ret
;
;**********
;* ErrMsg *
;**********
;An error message is generated from the code in AL.
;
ErrMsg	proc	near
	push	AX
	Sys	9,SignOn
	pop	AX
	LodOff	DX,Err1		;This msg for errs 1 and 2
	cmp	AL,3
	jc	EM
	LodOff	DX,Err2		;this one for errs 3 and 4.
EM:	Sys	9
	call	DspFN
	ret
ErrMsg	endp
;
;***********
;* $OVLYxU *
;***********
;This routine is driven off of the Method variable.  It is initialized to zero
;as the overlay loader is allowed to use the file name as is.  On subsequent
;tries the various ways of modifying the file name in an effort to find the
;overlay are attempted.  These all involve adding a prefix to the file name,
;like a drive specifier or a directory name.  The last method tried is to
;ask the operator to enter a prefix.  If the operator so instructs, the
;overlay loader is told to give up and terminate the program.
;
$OVLYMU	proc	near
	cld			;all increments forward.
	or	AL,AL		;first attempt on this overlay file?
	jnz	Error
	mov	Method,0	;yes, start with PATH.
	mov	Pflag,0		;set DspFN to avoid displaying prefix.
	mov	BX,EnvOff	;set initial environment ptr
	mov	TryEnv,BX
	jmp	short Return	;try file name as is.
;
Error:	test	Method,-1	;no, has environment been tried yet?
	jnz	Prf
	call	TryPth		;try next environment string
	jnc	Return
	inc	Method		;try default prefix, once,
	jmp	short Prf2
Prf:	call	ErrMsg		;Tell operator what problem is,
	mov	Pflag,1		;display file name prefixes from now on,
	call	GetPrf		;and ask for new file name prefix.
	jc	GiveUp
Prf2:	call	SetPrf		;append current prefix to file name.
;
Return:	mov	AL,0		;Tell loader to try current file name.
	ret
GiveUp:	mov	AL,1		;Operator wants to terminate program.
	ret	
;
$OVLYMU	endp

OVcode	ends

	end
