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 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