;----------------------------------------------------------
; Replacement WSTUB.EXE (Watcom C++'s DOS4GW loader stub)
; that will shrink any Watcom DOS4GW program by 10K (!)
;
; Written by Tenie Remmel.  Assemble with TASM.
;----------------------------------------------------------

Ideal
Model Small
Stack 400h
CodeSeg
Assume DS:_TEXT

Start:      jmp Begin

D4GPath$    db 'DOS4GPATH',0
Path$       db 'PATH',0
ExecName$   db 'DOS4GW.EXE',0

Failed$     db 'Stub exec failed$'

ParmBlock   dw 0,offset CmdBuf
            dw 0,5Ch,0,6Ch,0

Begin:      mov ah,4Ah              ;Only need 8K memory
            mov bx,200h
            int 21h

            push cs                 ;DS = CS
            pop ds
            mov [SaveBuf],es        ;Save PSP seg
            mov es,[es:2Ch]         ;ES = environment

            mov ax,offset D4GPath$  ;Get environment string
            call GetEnv
            jc Search2              ;Not there?

            mov si,ax               ;Set up for CopyLoop1
            mov di,offset PathBuf

CopyLoop1:  seges lodsb             ;Copy byte
            mov [di],al
            inc di
            test al,al              ;Loop while not zero
            jnz CopyLoop1

            mov si,offset PathBuf   ;Set up for DotLoop
            xor ah,ah

DotLoop:    lodsb                   ;Load byte
            test al,al              ;Check for null
            jz DotDone
            cmp al,'.'              ;Check for dot
            jne DotLoop

            cmp [byte si],'e'       ;Must be executable
            jne DotLoop             ;so check for 'E'
            cmp [byte si],'E'
            jne DotLoop

            jmp Load                ;Go load it

DotDone:    mov ax,offset D4GPath$  ;Look in DOS4GPATH
            call FindFile
            jnc Load
            
Search2:    mov ax,offset Path$     ;Look in normal PATH
            call FindFile
            jnc Load

            mov si,offset ExecName$ ;Not found, use current dir
            mov di,offset PathBuf

CopyLoop2:  lodsb                   ;Copy byte
            mov [di],al
            inc di
            test al,al              ;Loop while not zero
            jnz CopyLoop2

Load:       xor di,di               ;Set up for Arg0Loop
            xor al,al
            mov cx,-1

Arg0Loop:   repne scasb             ;Find double zero byte
            scasb
            jne Arg0Loop

            xchg si,di              ;SI = executable name
            add si,2                ;DI = command buffer
            mov di,offset CmdBuf+1
            mov cx,7Fh              ;127 max chars

CopyLoop3:  seges lodsb             ;Copy byte
            mov [di],al
            inc di
            test al,al              ;Loop while not zero
            loopnz CopyLoop3

            mov [byte di-1],' '     ;Replace null with space
            mov es,[SaveBuf]        ;ES:SI = old command line
            mov si,81h

CopyLoop4:  seges lodsb             ;Copy byte
            mov [di],al
            inc di
            cmp al,0Dh              ;Loop until CR
            loopnz CopyLoop4

            neg cx                  ;CX = length
            add cx,7Eh

            mov [CmdBuf],cl         ;Set length

            push ds                 ;ES:BX = EXEC parameter block
            pop es
            mov bx,offset ParmBlock

            mov [bx+4],ds           ;Set up parameter block
            mov [bx+8],ds
            mov [bx+12],ds

            mov [SaveBuf],sp        ;Save the stack pointers
            mov [SaveBuf+2],ss

            mov ax,4B00h            ;Execute the file
            mov dx,offset PathBuf
            int 21h
            jc Error                ;Error?

            mov ss,[cs:SaveBuf+2]   ;Load stack
            mov sp,[cs:SaveBuf]
Quit:       mov ax,4C00h            ;Exit to DOS
            int 21h

Error:      mov ah,9                ;Output message
            mov dx,offset Failed$
            int 21h
            jmp Quit

;----------------------------------------------------------
; GetEnv - get environment variable
;          supply   AX = ptr. to key string, ES = segment
;          returns  AX = ptr. to data or CF set on error

GetEnv:     push si di cx dx        ;Save registers

            mov dx,ax               ;DX = key
            xor di,di               ;DI = environment

GEloop:     mov si,dx               ;SI = key
            mov cx,-1               ;Compare strings
            repe cmpsb

            cmp [byte si-1],0       ;Found it?
            jne GElb
            cmp [byte es:di-1],'='
            clc                     ;Clear carry
            je GEdone

GElb:       xor al,al               ;Skip this value
            repne scasb
            cmp [byte es:di],0      ;Out of strings?
            jne GEloop

            stc                     ;Not found

GEdone:     mov ax,di               ;AX = pointer

            pop dx cx di si         ;Restore registers
            ret                     ;Return

;----------------------------------------------------------
; FindFile - Find ExecName$ in path
;          supply   AX = ptr. to key string, ES = segment
;          returns  PathBuf = file or CF set on error

FindFile:   push ax bx dx si di     ;Save all registers

            call GetEnv             ;Get environment string
            jc FFquit

            mov si,ax               ;SI = string

FFloop:     mov di,offset PathBuf   ;DI = path buffer

FFcopy1:    seges lodsb             ;Copy byte
            mov [di],al
            inc di
            test al,al              ;Zero?
            jz FFerror
            cmp al,';'              ;Semi-colon?
            jne FFcopy1

FFcont1:    dec di                  ;Move past null

            mov al,'\'              ;Slash already there?
            cmp [di-1],al
            je FFskip
            mov [di],al             ;Add last slash
            inc di

FFskip:     push si                 ;Save SI

            mov si,offset ExecName$ ;Copying filename
            
FFcopy2:    lodsb                   ;Copy byte
            mov [di],al
            inc di
            test al,al              ;Loop while not zero
            jnz FFcopy2

            pop si                  ;Restore SI

            mov dx,offset PathBuf   ;Try to open this file
            mov ax,3D00h
            int 21h
            jc FFloop               ;Jump if error

            mov bx,ax               ;Close the file
            mov ah,3Eh
            int 21h

FFquit:     pop di si dx bx ax      ;Restore registers
            ret                     ;Return

FFerror:    stc                     ;Return with error
            jmp FFquit

PathBuf     db 130 dup(?)
CmdBuf      db 130 dup(?)

SaveBuf     dw ?,?

End Start
