home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 18 REXX
/
18-REXX.zip
/
rxfiles.zip
/
rxdostry.asm
< prev
next >
Wrap
Assembly Source File
|
1997-08-14
|
20KB
|
546 lines
;-----------------------------------------------------------------------
; RXDOSTRY.RX by (MASM 6.0) ML /AT /Fe RXDOSTRY.RX RXDOSTRY.ASM
;
; intended to be called by PC DOS 7 REXX as external function:
; say 'CHOICE return code =' RXDOSTRY( 'CHOICE /C:ABC' )
;
; Note especially how the SIGINT handler of REXX is replaced by
; the old handler in place before REXX started (test CHOICE ^C)
;-----------------------------------------------------------------------
code segment para public 'CODE'
assume cs:code, ds:code, es:code, ss:code
org 16h
RXpid dw ? ;_psp:0x16 parent (REXX) pid
org 2Ch
envseg dw ? ;_psp:0x2C environment segment
org 54h
DOSREXX4 dd ? ;_psp:0x54 'REXX' signature
SHVENTRY dd ? ;_psp:0x58 shared variable handler
org 82h
RXARGC dw ? ;_psp:0x82 number of arguments
RXARGV dd ? ;_psp:0x84 arg.s (length, pointer)
RXRESULT dd ? ;_psp:0x88 RESULT buffer (256 bytes)
org 100h ;COM entry point at CS:100
start: jmp stack ;set stack, release memory
;-----------------------------------------------------------------------
pathptr dd ? ;address actual PATH
execpar dw ? ;segment environment
dd ? ;pointer command line
fcb1 dd 5Ch ;pointer own 1st FCB
fcb2 dd 6Ch ;pointer own 2nd FCB
exe db '.\????????.EXE EXE' ;4 blanks for parse FCB
com db '.\????????.COM COM' ;EXE, COM for test type
COMSIZE equ 130 ;128 + 2 (count + CR resp. name + blank)
comline db COMSIZE dup (0Dh) ;command arguments end with CR
command db COMSIZE dup (0) ;buffer for search command file
pathtxt db 'PATH=',0 ;search PATH setting
arg1len dw ? ;length of first and only REXX argument
argerr db 13,10,7,'invalid REXX argument',13,10,0
errname db 13,10,7,'illegal drive or ambiguous command',13,10,0
exectext db 13,10,7,'DOS cannot execute given command',13,10,0
missing db 13,10,7,'cannot locate command "',0
misscom db '" or "',0
missend db '"',13,10,0
;-----------------------------------------------------------------------
main proc near ;enter after initialization
cmp word ptr DOSREXX4+2,'XX'
jne badarg
cmp RXARGC,1 ;one and only one REXX argument string
je envir
badlen: push es
pop ds
badarg: mov dx,offset argerr
badmsg: call message
jmp fail ;exit
envir: mov bx,envseg ;PSP offset 2Ch environment
mov execpar,bx ;own environmemt segment BX
mov word ptr fcb1+2,ds
mov word ptr fcb2+2,ds
lds si,RXARGV
mov cx,[si] ;length 1st argument
cmp cx,COMSIZE-2 ;2 bytes count + CR
ja badlen ;argument too long
push cx ;keep length for later
lds si,[si+2] ;address 1st argument
mov di,offset comline+1
rep movsb ;copy to comline+1
;comline: CR + REXX_argument_string + CR
;comline: CR + trash + command + space + args + CR
mov ds,es:RXpid ;parent (REXX) PSP
mov si,0Eh ;PSP offset INT 23h
lds dx,[si] ;parent old INT 23h
mov ax,2523h ;set SIGINT handler
int 21h
push es
pop ds
;;;;;;;; mov bx,execpar ;BX points to environment
call initpath ;search PATH for pathptr
mov si,offset comline+1
pop cx ;restore saved length
testarg: jcxz badarg ;any character left ?
dec cx
lodsb
cmp al,' ' ;skip white space at
jbe testarg ;begin of command name
dec si ;SI = 1st valid char.
inc cx ;CX = remaining length
mov di,offset comline
;comline: CR + trash + command + space + args + CR
;ES:DI at CR + trash + command + space + args + CR
;DS:SI at command + space + args + CR
cominc: cmp byte ptr [si],' '
jbe comgot ;copy 1st argument to
movsb ;command name buffer
loop cominc
comgot: xor ax,ax
stosb ;AL 0 to name buffer
;comline: command + 0 + trash + space + args + CR
;ES:DI at trash + space + args + CR
;DS:SI at space + args + CR
lea bx,[si-1] ;rest length of arguments
mov [bx],cl ;to new command line size
mov word ptr execpar+02,bx
mov word ptr execpar+04,ds
;comline: command + 0 + ? + size + space + args + CR
;DS:BX at size + space + args + CR
;DS:SI at space + args + CR
les di,fcb1 ;PSP offset 5Ch is 1st FCB
mov ax,2901h ;parse 2nd argument to FCB
int 21h ;(skip leading separators)
les di,fcb2 ;PSP offset 6Ch is 2nd FCB
mov ax,2901h ;parse 3rd argument to FCB
int 21h ;(incompatible simplified)
;-----------------------------------------------------------------------
; parse command to file name
push ds
pop es
mov dx,offset comline
call strlen ;lenght of command name
mov di,dx ;scan end of path in DI
mov al,'\'
haspath: mov si,di ;keep end of path in SI
jcxz endpath ;skip specified path
repne scasb ;scan path character AL
jz haspath
endpath: xchg dx,si ;keep end of path in DX
mov cx,dx ;determine length in CX
sub cx,si ;(use path length excl.
push cx ; command name if given)
mov si,dx
mov di,offset com ;parse '????????.COM',0
call parse ;or explicit extension
mov si,dx
mov di,offset exe ;parse '????????.EXE',0
call parse ;or explicit extension
pop cx ;restore path length CX
or al,al
jnz badname ;bad drive or '*' / '?'
mov di,offset com+2
call comorexe ;file extension 'COM' ?
je search
mov di,offset exe+2
call comorexe ;file extension 'EXE' ?
je search
badname: mov dx,offset errname
jmp badmsg ;exit
;-----------------------------------------------------------------------
; search command (given type or COM / EXE, given path or PATH)
search: mov bx,offset command
jcxz nopath ;no path specified ?
mov si,offset comline
mov di,bx ;command file target
rep movsb ;copy specified path
mov dx,offset com+2
push di ;keeping target DI
call strcpy ;try xxx.COM at DI
pop di ;restore target DI
mov dx,bx ;command file path
mov ax,4300h ;test COM existence:
int 21h ;get file attribute
jnc gotfile
mov dx,offset exe+2
call strcpy ;try xxx.EXE at DI
mov dx,bx ;command file path
mov ax,4300h ;test EXE existence:
int 21h ;get file attribute
jnc gotfile
mov dx,offset missing
push bx
call message ;cannot find command
pop dx ;with specified path
call message
mov dx,offset missend
jmp badmsg ;exit
nopath: mov dx,offset com ;test COM existence:
mov ax,4300h ;get file attribute
int 21h
jnc gotfile
mov dx,offset exe ;test EXE existence:
mov ax,4300h ;get file attribute
int 21h
gotfile: jnc doit
call nextpath ;DI: next PATH token
jc nofile ;command file target
mov dx,offset com+2
push di ;keeping target DI
call strcpy ;try xxx.COM at DI
pop di ;restore target DI
mov dx,bx ;command file path
mov ax,4300h ;test COM existence:
int 21h ;get file attribute
jnc gotfile
mov dx,offset exe+2
call strcpy ;try xxx.EXE at DI
mov dx,bx ;command file path
mov ax,4300h ;test EXE existence:
int 21h ;get file attribute
jmp gotfile ;try next PATH token
nofile: mov dx,offset missing
call message ;cannot find command
mov dx,offset com+2
call message ;COM
mov dx,offset misscom
call message ;or
mov dx,offset exe+2
call message ;EXE
mov dx,offset missend
jmp badmsg ;exit
;-----------------------------------------------------------------------
; execute DOS external command, common exit handling
savesp dw (?) ;DOS 2.x exec can destroy SP
savess dw (?) ;DOS 2.x exec can destroy SS
doit: push ds
push es
mov cs:savess,ss
mov cs:savesp,sp ;DS:DX ASCIIZ command
mov ax,4B00h ;ES:BX exec parameter
mov bx,offset execpar
int 21h ;DOS exec function in
cli ;DOS 2.x destroys all
mov ss,cs:savess ;no interrupts during
mov sp,cs:savesp ;restauration DS = ES
pop es ;and stack SS:SP
pop ds
sti ;interrupts now okay
jnc didexec ;no carry: exec done
mov dx,offset exectext
jmp badmsg ;exit
didexec: les di,RXRESULT
mov ah,4Dh ;get last exit code
int 21h
mov ah,0 ;AX = exit code 0..255
mov cl,100 ;AL = quotient 0.. 2
div cl ;AH = remainder 0.. 99
mov cx,'00'
or al,cl
cmp al,ch
je lt_100
xor ch,ch
stosb ;e.g. 1 of exit code 123
lt_100: mov al,ah
aam ;adjust remainder 0..99
xchg al,ah
or al,cl
cmp al,ch
je lt_010
stosb ;e.g. 2 of exit code 123
lt_010: mov al,ah
or al,cl
stosb ;e.g. 3 of exit code 123
xor al,al ;return code, AL := 0
stosb ;ASCIIZ result string
jmp exit
fail: mov al,1 ;return code, AL := 1
exit: mov ah,4Ch ;terminate with RC AL
int 21h
main endp
;-----------------------------------------------------------------------
initpath proc near ;search for path in environment BX
push ds ;modifies AX, CX, DI, SI
mov word ptr pathptr+2,bx
mov ds,bx ;environment segment
xor ax,ax ;DS:SI start BX:0000
mov si,ax
scanit: mov cx,5
mov di,offset pathtxt
repe cmpsb ;look for 'PATH='
mov cx,si ;terminate search at segment limit
not cx ;this will work for length < 64 KB
jne skipit ;CMPSB NOT changed 'PATH=' found ?
pop ds ;restore own data segment
mov word ptr pathptr+0,si
ret ;BX:SI is real PATH begin
skipit: lodsb ;look for terminating NUL byte
or al,al
loopnz skipit
jcxz envend ;environment segment > 64 KB ?
cmp [si],al ;go on with search
jne scanit ;unless double NUL
envend: pop ds ;restore own data segment
lea si,[pathtxt+5]
mov word ptr pathptr+0,si
mov word ptr pathptr+2,ds
ret ;DS:SI for NUL PATH dummy
initpath endp
;-----------------------------------------------------------------------
nextpath proc near ;search for path in environment
push ds ;modifies AX, DI, SI
mov ah,11111111b ;yet no character mark
mov di,offset command
lds si,pathptr
test ah,[si]
jnz incpath ;handle ASCIIZ string end
pop ds ;restore own data segment
stc ;indicate PATH end (carry)
ret
incpath: lodsb
cmp al,';'
je textend ;handle PATH token end ';'
or al,al
jz textend ;handle ASCIIZ string end
stosb
mov ah,al ;mark for got a character
jmp incpath
textend: pop ds ;restore own data segment
mov word ptr pathptr+0,si
cmp ah,11111111b
jz nextpath ;oops, empty path token ?
cmp byte ptr [di-1],':'
jz pathend ;expect DOS disk character
mov al,'\'
cmp [di-1],al ;':' or DOS path character
jz pathend ;otherwise patch '\'
stosb
pathend: clc ;indicate token (no carry)
ret ;DI points to end of token
nextpath endp
;-----------------------------------------------------------------------
parse proc near ;parse name SI to filename.ext DI
push di ;modifies AX, CX, DI, SI
inc di ;skip '.' in target data
mov al,'\'
stosb ;reserve e.g. '.\' or 'A:'
mov ax,2908h ;parse command name SI
int 21h ;to DI, keep extension
or al,al
jz parseok ;'*' or '?' or bad drive ?
pop di ;restore initial target
ret ;AL > 0 indicates error
parseok: push di ;keep target
mov cx,8 ;copy filename to begin
lea si,[di+1] ;i.e. overwrite drive X
rep movsb
mov al,' ' ;AL is terminator blank
stosb
pop di ;scan for blank end and
mov cx,9 ;replace by point
repne scasb
mov byte ptr [di-1],'.'
push di ;keep target
mov cx,3 ;copy file extension SI
rep movsb
pop di ;scan for blank end and
mov cx,4 ;replace by NUL
repne scasb
xor ax,ax
mov [di-1],al
pop di ;restore initial target
mov si,offset comline
cmp byte ptr [si+1],':'
jnz parsend ;replace dummy path
movsw ;by specified drive
parsend: ret ;indicate okay AL 0
parse endp
;-----------------------------------------------------------------------
comorexe proc near ;file type DI+16 in identifier DI ?
push cx ;modifies AL, DI, SI
mov al,'.' ;keep CX, AH
lea si,[di+16]
mov cx,9 ;scan type following guaranteed '.'
repne scasb
mov cx,3 ;test type (uppercase parse result)
repe cmpsb ;for simplicity assume 3 bytes type
pop cx
ret ;flag E equal types or NE not equal
comorexe endp
;-----------------------------------------------------------------------
strlen proc near ;return length ASCIIZ string ES:DX
xchg di,dx ;modifies AX, CX
mov cx,di ;keep DX, DI, ES
not cx ;terminate search at segment limit
push di ;this will work for length < 64 KB
xor al,al
repne scasb ;search NUL
mov cx,di ;DI points behind NUL (or is NULL)
pop di ;restore DI
sub cx,di ;length inclusive NUL
dec cx ;length exclusive NUL
xchg dx,di ;restore DX
ret ;returns CX string length
strlen endp
;-----------------------------------------------------------------------
strcpy proc near ;ASCIIZ string DS:DX to ES:DI
push cx ;modifies AX, DI
push es ;keep CX, DX, ES
push ds
pop es ;set ES = DS
call strlen ;string length CX
pop es ;load old ES
jcxz nulcpy
push di ;target + length
add di,cx ;in segment ES ?
jnc allcpy ;then copy all
sub cx,di ;else truncate
allcpy: pop di ;target DI
push si ;saving SI
mov si,dx ;source DX
rep movsb
pop si
nulcpy: mov [di],cl ;target terminator
pop cx ;DI is end of copy
ret
strcpy endp
;-----------------------------------------------------------------------
message proc near ;ASCIIZ string DS:DX to STDERR
push ax ;modifies BX, CX
push es ;keep AX, DX, DS, ES
push ds
pop es ;set ES = DS
call strlen ;CX = strlen( ES:DX )
pop es ;load old ES
mov bx,2 ;ASCIIZ string DS:DX to STDERR
mov ah,40h
int 21h
pop ax
ret
message endp
;-----------------------------------------------------------------------
align 16
stkparas equ 32 ;stack size 512 = 32 * 16
stack label near ;initialise *.com program
mov bx,offset stack + 16 * stkparas
mov sp,bx ;new stack 100h above init
mov cl,4
shr bx,cl ;used number of paragraphs:
mov ah,4ah ;modify allocated memory to
int 21h ;needed size i.e. free rest
jmp main ;current SP must be beyond
;-----------------------------------------------------------------------
code ends
end start ;program entry point