;*****************************************************************************
; Filename: STUB.ASM
;   Author: Adam Seychell
;  Version: 1.00
;  Created: 1994.09
;  Updated: 1995.Feb.1
;   Note 1: This code has been optimized for size ( current size 290 bytes).
;   Note 2: After linking this program use the EXERID utility to remove
;           wasted header space.
;
; History and changes are documented at the end of this file.
;*****************************************************************************
;            Stub loader for DOS32 executibles.
;
; This stub loader attempts to loads and execute DOS32.EXE.
;  and is searched in the following order.
;
;  1) The directory in which the executible exists ( i.e this stub file )
;  2) Directories entries in the PATH environment varible.
;
;  The final EXE will be this stub EXE file and the 32bit executable image
;  appended together.
;
;*****************************************************************************
.8086

Stub_Program  SEGMENT stack 'STACK'
Assume DS:Stub_Program,CS:Stub_Program


Stub_Loader:


   ;
   ;  Free program memory
   ;
        mov     bx,cs
        mov     ax,sp
        mov     cl,4
        shr     ax,cl
        inc     ax
        add     bx,ax                           ; BX = top of stack paragraph
        mov     ax,ds                           ; Sub PSP address
        sub     bx,ax
        mov     ah,4Ah
        int     21h

        push    cs                      ; Load DS with data segment
        pop     ds


   ;
   ; Fuxup rest of the Execute Parameter Table.  note: ES -> PSP segment
   ;
        mov     word ptr EXEC_Params[04h],es      ; command tail segment
        mov     word ptr EXEC_Params[08h],es      ; FCB 1 segment
        mov     word ptr EXEC_Params[0Ch],es      ; FCB 2 segment


        mov     es,es:[2Ch]             ; Load ES with environment segment.


   ;
   ; Look for the 'PATH=' envrinment string;
   ;
        cld
        xor     di,di
Next_Var:
        mov     si,Offset Path_String
        mov     cx,5
        cmp     byte ptr es:[di],0
        je   Got_Envir
        repe    cmpsb                   ; Compare DS:SI with ES:DI
        jne NoPATH
        mov     Path_Ofs,di           ; Save the PATH varible offset if Equal
NoPATH: xor     al,al                   ; Goto next environment varible
        mov     ch,-1
        repne   scasb
        jmp  Next_Var


Got_Envir:                              ; ES:DI points to end of environment

 ; 
 ; Copy .EXE path to the file name buffer
 ;
        cmp     byte ptr es:[di+4],':'
        jne  Try_path_loop              ; Assume there's no path is no ':'
        mov     si,Offset File_Name
GetEXEpath:
        mov     al,es:[di+3]
        inc     di
        mov     ds:[si],al
        inc     si
        cmp     al,'\'
        jne    _J87
         mov    bx,si           ; Save SI
_J87:
        and     al,al
        jnz     GetEXEpath

        mov     si,bx
        jmp     Exec_It

;
; The main loop when trying to load and execute DOS32.EXE with each path
; entry in the 'PATH=...' environment string.
;
Try_path_loop:
        mov     di,Path_Ofs
        And     di,di
        jl   Load_error                 ; Error if no path varible was found.
        cmp     al,2
        je   Try_again                  ; Try again if file not found.
        cmp     al,3
        jne  Load_error                 ; Try again if path not found.
Try_again:


     ;
     ; Copy a path entry to the file name buffer
     ;
        mov     si,Offset File_Name
Copy_path:
        mov     al,es:[di]
        inc     di
        cmp     al,';'
        je done_pen
        cmp     al,' '
        je done_pen
        and     al,al
        jz  done_pen_End
        mov     [si],al
        inc     si
        jmp     Copy_path

done_pen_End:
         mov      di,-1
done_pen:
        mov     Path_Ofs,di


     ;
     ; Append the string 'DOS32.EXE' to the file name buffer
     ;
        cmp     Byte Ptr [si-1],'\'        ; If path dosn't contain a '\'
        je Exec_It                         ; then put one it.
         mov    Byte ptr [si],'\'
         inc    si
Exec_It:
        push    es                         ; Save ES
        push    cs
        pop     es
        mov     di,si
        mov     si,Offset DOS32_EXE
        mov     cx,10
        rep     movsb


   ;
   ; Go and Load then Execute DOS32.EXE
   ;
        mov     bx,Offset EXEC_Params
        mov     dx,Offset File_name
        mov     ax,4B00h
        int     21h
        pop     es                    ; Restore ES
        jc     Try_path_loop

        Mov     ah,4Dh                ; Get return code from DOS32 aplication
        Int     21h

exit:
        Mov     ah,4ch                ; Terminate to DOS
        Int     21h




 ;
 ; Exit with an error message
 ;

Load_error:
        mov     dx,Offset Exec_Error_Mesg
        mov     ah,9
        int     21h
        xor     al,al
        jmp exit


Path_String     DB    	'PATH='
Path_Ofs        DW    	-1
Exec_Error_Mesg DB    	'Cannot find '
DOS32_EXE       DB      'DOS32.EXE',0,'in path',10,13,36
EXEC_Params     DW      0            	; childs Environemnt segment
                DW      80h,0           ; childs command tail seg:ofs
                DW      5Ch,0           ; FCB 1  seg:ofs
                DW      6Ch,?           ; FCB 2  seg:ofs
align 2
File_name       DB      128 DUP (?)     ; 128 chars for file the name.

                DB      100     dup (?)                 ; The stack space
The_Stack       DW ?

Stub_Program    ENDS

End  Stub_Loader

1994.Nov.11 : Made the return code equal to the return code from
              the DOS32 application. This would of caused problems
              with applications that rely on the return code.

1995.Feb.1  : Fixed bug in Execute parameter table. The segment
              values were not set correctly.
