mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
202 lines
5.0 KiB
202 lines
5.0 KiB
code segment 'CODE'
|
|
; NOTE: this app does have a stack, it just is not used here. The
|
|
; stack is setup by exemod so that it does not take any more disk
|
|
; space since only the MIN/MAXALLOC and SS/SP fields are set.
|
|
|
|
assume cs:code, ds:nothing, es:nothing, ss:nothing
|
|
|
|
szSlm db "slm.exe",0 ; name we will invoke
|
|
cbSlm = 8 ; size including 0
|
|
epb dw 0, 80h, ?, 5ch, ?, 6ch, ? ; exec param block; ? = psp later
|
|
szOurs dd 0 ; far ptr to name used to invoke this program
|
|
szTry db 128 dup(0) ; buffer for exec attemp.
|
|
|
|
sdExecErr db "Cannot execute slm.exe",13,10,"$"
|
|
sdDosErr db "DOS 3.x or newer is required",13,10,"$"
|
|
sdCmdErr db "Command line is too long, please re-issue as two commands",13,10,"$"
|
|
|
|
exec_begin:
|
|
mov ax,cs
|
|
mov ds,ax
|
|
assume ds:code ; ds = code, es = Program Segment Prefix
|
|
|
|
mov ah,30h ; get dos version number
|
|
int 21h
|
|
cmp al,3 ; >= 3 ?
|
|
jae correct_dos
|
|
jmp dos_err ; sorry folks (ds == code!)
|
|
correct_dos:
|
|
|
|
; setup exec parameter block to refer to current info by putting
|
|
; segment of psp in several places in exec param block
|
|
mov [epb+4],es ; es:80h = same command line as parent
|
|
mov [epb+8],es ; es:5ch = same fcb1 as parent
|
|
mov [epb+12],es ; es:6ch = same fcb2 as parent
|
|
|
|
mov ax,es
|
|
mov ds,ax
|
|
assume ds:nothing ; ds = es = Program Segment Prefix
|
|
|
|
; find path used to invoke the program
|
|
mov es,ds:[2ch]
|
|
xor di,di ; es:di = environment
|
|
xor ax,ax ; ax = 0 for scans
|
|
mov cx,-1 ; env < 64k!
|
|
cld ; forward march
|
|
|
|
test_end:
|
|
scasb ; skip first byte and test
|
|
je end_env ; jump if empty string and exit loop
|
|
|
|
repnz scasb ; skip string and null terminator; ax = 0
|
|
jmp short test_end
|
|
|
|
end_env:
|
|
add di,2 ; es:di = name used to run this program
|
|
|
|
mov word ptr [szOurs],di
|
|
mov word ptr [szOurs+2],es ; szOurs = pointer to our name
|
|
|
|
; find length of length of szOurs
|
|
mov cx,-1 ; prepare cx for counting string; ax = 0!
|
|
repnz scasb
|
|
inc cx
|
|
neg cx ; cs = length of name of our program + 1 (blank)
|
|
and cx,127 ; truncate for safety
|
|
mov bx,cx ; bx = length + 1
|
|
|
|
; reset es to psp
|
|
mov ax,ds
|
|
mov es,ax
|
|
|
|
; shift command line. Es==Ds which is Program Segment Prefix
|
|
mov di,0ffh ; es:di = last byte of command area
|
|
mov si,di
|
|
sub si,bx ; ds:si = last usable byte of command
|
|
mov cx,127
|
|
sub cx,bx ; cx = 127 - (length + 1) -> amount to move
|
|
std ; move backwards
|
|
rep movsb
|
|
|
|
; install new first param preceeded by a blank
|
|
lds si,[szOurs] ; ds:si = name of our program;
|
|
mov di,81h ; es:di location in psp of command line
|
|
mov al,' '
|
|
cld ; forward store/move
|
|
stosb ; put blank at start; inc di
|
|
|
|
mov cx,bx ; cx = length of name + 1
|
|
dec cx
|
|
rep movsb ; copy name after blank
|
|
|
|
add byte ptr es:[80h],bl ; increment size of command
|
|
cmp byte ptr es:[80h],126
|
|
jna length_ok ; jump if > 126
|
|
|
|
mov ax,cs
|
|
mov ds,ax
|
|
assume ds:code
|
|
|
|
mov ah,9h ; print $-terminated string to console
|
|
mov dx,offset sdCmdErr
|
|
int 21h
|
|
mov al,1 ; set error code
|
|
jmp short exec_exit
|
|
|
|
assume ds:nothing ; back the way it was
|
|
|
|
length_ok:
|
|
|
|
; copy our name to szTry
|
|
mov ax,cs
|
|
mov es,ax ; es == cs
|
|
assume es:code
|
|
|
|
mov di,offset szTry ; es:di = buffer for path to exec
|
|
lds si,[szOurs] ; ds:si = our name
|
|
|
|
mov cx,bx ; cx = length of name + 1
|
|
dec cx
|
|
rep movsb ; copy our name(ds:si) to szTry(es:di)
|
|
|
|
mov ax,cs
|
|
mov ds,ax
|
|
assume ds:code
|
|
|
|
; do not search past drive if one
|
|
dec bx
|
|
cmp byte ptr [szTry+1],':' ; do we have a drive spec ?
|
|
jne after_drive
|
|
dec bx
|
|
dec bx
|
|
after_drive:
|
|
|
|
dec di ; point to last character
|
|
mov si,di ; save copy in si
|
|
std
|
|
|
|
; scan backwards to find last /; es:di = end; bx = length
|
|
mov cx,bx
|
|
mov al,'/'
|
|
repne scasb ; stops at 1 before start or /
|
|
jne no_slash
|
|
inc di
|
|
no_slash:
|
|
inc di ; es:di = place to put new name
|
|
|
|
; scan backwards for last \; es:di = last /; es:si = end; bx = length
|
|
xchg si,di ; trade first one guess with start
|
|
mov cx,bx
|
|
mov al,'\'
|
|
repne scasb ; stops at 1 before start or \
|
|
jne no_back
|
|
inc di
|
|
no_back:
|
|
inc di
|
|
|
|
; find out which one is higher in memory.
|
|
cmp si,di
|
|
jb use_di
|
|
mov di,si ; use si
|
|
use_di:
|
|
|
|
; copy new name onto end; es:di = buffer with "path/" before
|
|
mov si,offset szSlm ; ds:si = name of program we are trying for
|
|
mov cx,cbSlm ; cx = size including trailing 0
|
|
cld
|
|
rep movsb
|
|
|
|
; try exec'ing this name
|
|
mov dx,offset szTry ; ds:dx = file to execute
|
|
mov bx,offset epb ; es:bx = exec param block
|
|
|
|
mov ax,4b00h ; load and execute
|
|
int 21h
|
|
jae exec_ok ; jump if process executed correctly
|
|
|
|
mov ah,9h ; print $-terminated string to console
|
|
mov dx,offset sdExecErr ; ds:dx = error message
|
|
int 21h
|
|
|
|
exec_err:
|
|
mov al,1 ; set error code
|
|
jmp short exec_exit
|
|
exec_ok:
|
|
mov ah,4dh ; get terminate code
|
|
int 21h
|
|
or al,ah ; if not normal, set some bits in al
|
|
exec_exit:
|
|
mov ah,4ch ; exit with error code in al
|
|
int 21h
|
|
|
|
dos_err: ; ds == code
|
|
mov ah,9h ; print $-terminated string to console
|
|
mov dx,offset sdDosErr ; ds:dx = error message
|
|
int 21h
|
|
|
|
jmp short exec_err
|
|
|
|
; NOTREACHED
|
|
code ends
|
|
|
|
end exec_begin
|