home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
pcmag
/
vol7n03.arc
/
RUN.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-02-16
|
22KB
|
498 lines
;----------------------------------------------------------------------
; RUN.ASM
; Format: RUN [/C][/S][d:][directory] filename [arguments]
; /C = Change to the directory and run
; /S = Stay in current directory and run
; Default is /S
;----------------------------------------------------------------------
CODE SEGMENT ;********************************;
ASSUME CS:CODE,DS:CODE ;* *;
ORG 100H ;* Requires MASM 2.0 or later *;
;* Remember to EXE2BIN *;
START: JMP BEGINNING ;* *;
;********************************;
; DATA AREA
; ---------
COPYRIGHT DB "RUN 1.0 (c) 1987 Ziff Communications Co.",13,10
DB "PC Magazine ",254," Michael J. Mefford",13,10,"$",26
CURRENT_DISK DB ?
WORKING_DISK DB 0FFH
FILE_START DW ?
FILENAME_END DW ?
ARGUMENTS DW ?
PATH_END DW 0
CHANGE_FLAG DB 0
BAT_FLAG DB 0
SYNTAX DB 13,10,"Syntax: RUN [/C][/S][d:][directory] filename [arguments]"
DB 13,10,"/C = Change to the directory and run"
DB 13,10,"/S = Stay in current directory and run"
DB 13,10,"Default is /S"
CR_LF DB 13,10,"$"
FAIL DB 13,10,"Can't find $"
SEARCHING DB 13,10,"Searching for $"
DELIMITERS DB 9,13,32,"/<>."
EXE DB "EXE",0
COM DB "COM",0
BAT DB "BAT",0
ROOT DB "\",0
STAR_DOT_STAR DB "*.*",0
PARENT DB "..",0
COPY DB " /C "
COMSPEC DB "COMSPEC="
STACK_SEG DW ?
STACK_PTR DW ?
PARAMETER_BLOCK LABEL WORD
ENVIRONMENT DW 0
COM_LINE_PTR DW PARAMETER,?
FCB_1ST DW FCB_5CH, ?
FCB_2ND DW FCB_6CH, ?
;----------------------------------------------------------------------------;
; Some housekeeping first. Since we will be changing the default drive ;
; and directory to the requested drive and directory, we need to save the ;
; current defaults, so they can be restored. Change the default DTA. ;
; Move the stack and deallocate memory so we have room to spawn the program. ;
;----------------------------------------------------------------------------;
; CODE AREA
; ---------
BEGINNING:
MOV AH,9
MOV DX,OFFSET COPYRIGHT
INT 21H
CLD ;String moves forward.
CALL GET_DRIVE ;Get current drive.
MOV CURRENT_DISK,AL ;Save.
MOV SI,OFFSET CURRENT_DIR ;Get current directory.
CALL GET_DIR
MOV DX,OFFSET DTA ;Move the disk transfer address
MOV AH,1AH ; to the end of code to protect
INT 21H ; command line parameters at 80h.
MOV SP,OFFSET CODE_END ;Move the stack down to the
MOV BX,SP ; end of code segment.
ADD BX,15 ;Round up paragraph size.
MOV CL,4
SHR BX,CL
MOV AH,4AH ;Deallocate rest of memory.
INT 21H
;--------------------------------------------------;
; Parse the command line parameters. Start by ;
; scanning off spaces and RUN's switch characters. ;
;--------------------------------------------------;
MOV SI,80H ;Point to command line parameters.
LODSB
CMP AL,0 ;Are there any?
JZ BAD_SYNTAX ;If no, exit.
NEXT_LEADING: LODSB ;Get a byte.
CMP AL,"/" ;Is it a switch character?
JNZ CK_CR ;If no, check if end.
LODSB ;Else, get switch character.
CMP AL,13 ;Make sure not end.
JZ BAD_SYNTAX
AND AL,5FH ;Capitalize.
CMP AL,"C" ;Is it "C"?
JNZ CK_NOCHANGE
MOV CHANGE_FLAG,1 ;If yes, indicate to change dir.
CK_NOCHANGE: CMP AL,"S" ;Else, is it "S"?
JNZ NEXT_LEADING ;If no, next leading character.
MOV CHANGE_FLAG,0 ;Else, indicate not to change dir.
JMP SHORT NEXT_LEADING
CK_CR: CMP AL,13 ;Is it carriage return?
JNZ CK_LEADING ;If yes, bad syntax.
BAD_SYNTAX: JMP SYNTAX_EXIT
CK_LEADING: CMP AL,32 ;Is it a space or tab?
JBE NEXT_LEADING ;If yes, get next character.
DEC SI ;Else, adjust pointer back one.
PUSH SI ;Save as possible path request.
MOV FILE_START,SI ;Save as possible start of filename
;----------------------------------------------------;
; We now have the start of the run file. Next scan ;
; to the end of filename looking for a path request. ;
;----------------------------------------------------;
NEXT_PATH: LODSB ;Get a byte.
CMP AL,":" ;Drive request?
JNZ CK_PATH ;If no, check if directory.
MOV DL,[SI-2] ;Else, retrieve drive.
AND DL,5FH ;Capitalize.
SUB DL,"A" ;Convert to DOS format.
CALL CHANGE_DRIVE ;Change drive.
MOV FILE_START,SI ;Save as possible start of filename
JMP SHORT NEXT_PATH
CK_PATH: CMP AL,"\" ;Is it a path delimiter?
JNZ CK_DELIMITER ;If no, see if end of filename.
MOV PATH_END,SI ;Else, save as path end.
MOV FILE_START,SI ;Save as possible start of filename
CK_DELIMITER: MOV DI,OFFSET DELIMITERS ;Check for tab, carriage return,
MOV CX,6 ; space, switch, or redirection
REPNZ SCASB ; characters as filename end.
JNZ NEXT_PATH ;Continue until found.
DEC SI ;Else, adjust pointer back one.
MOV ARGUMENTS,SI ;Save as start of arguments.
;--------------------------------------------------;
; Parse the arguments for two file control blocks. ;
;--------------------------------------------------;
MOV DI,OFFSET FCB_5CH ;Point to first FCB storage.
MOV AX,2901H ;Parse and scan off leading
INT 21H ; separators.
MOV DI,OFFSET FCB_6CH ;Same for second FCB.
MOV AX,2901H
INT 21H
;----------------------------------------------------;
; Store working path so can be restored on exit. ;
; Store run filename stripping extension in process. ;
;----------------------------------------------------;
CALL GET_DRIVE ;Store working drive.
MOV WORKING_DISK,AL
MOV SI,OFFSET WORKING_DIR ;Store working directory.
CALL GET_DIR
MOV SI,FILE_START ;Store the run filename.
MOV DI,OFFSET FILENAME
NEXT_FILENAME: LODSB ;Get a byte.
PUSH DI
MOV DI,OFFSET DELIMITERS ;Are we at the end of filename
MOV CX,7 ; or encountered dot?
REPNZ SCASB
POP DI
JZ STORE_DOT ;If yes, done here.
STOSB
JMP SHORT NEXT_FILENAME
STORE_DOT: MOV AL,"."
STOSB
MOV FILENAME_END,DI ;Store end of filename.
;---------------------------------------------------------;
; If a path was found, change directory and search for ;
; run file. Else, do a diskwide search for the run file. ;
;---------------------------------------------------------;
POP DX ;Retrieve filespec start.
MOV SI,PATH_END ;Did we find a path?
CMP SI,0
JZ GLOBAL ;If no, do global search.
CMP BYTE PTR [SI-2],":" ;Else, check if special
JZ CHANGE_IT ; case of root directory.
CMP BYTE PTR [SI-2],32
JBE CHANGE_IT ;If yes, change directory.
DEC SI ;If no, adjust pointer.
CHANGE_IT: PUSH [SI] ;Save path end.
MOV BYTE PTR [SI],0 ;Convert to ASCIIZ for DOS.
CALL CHANGE_DIR ;Change directory.
POP [SI] ;Restore path end.
CALL CK_EXECUTABLE ;Search current directory
JNC RUN_IT ; for filename; run it if found.
JMP SHORT ERROR_EXIT ;Else, exit with message.
GLOBAL: CALL GLOBAL_SEARCH ;If no directory request, do a
JC ERROR_EXIT ; diskwide search for filename.
RUN_IT: CALL EXEC ;If found, execute it.
JMP SHORT EXIT
;-----------------------------------------------------------------------;
; This is the exit routine. Restore the defaults the way we found them. ;
;-----------------------------------------------------------------------;
ERROR_EXIT: MOV DX,OFFSET FAIL ;Display "Can't find ".
CALL PRINT_STRING
CALL PRINT_NAME ;Display filename.
SYNTAX_EXIT: MOV DX,OFFSET SYNTAX ;Display RUN syntax.
CALL PRINT_STRING
MOV AL,1 ;Error code of one.
JMP SHORT TERMINATE
EXIT: XOR AL,AL ;Error code of zero.
TERMINATE: PUSH AX ;Save error code.
CALL RESTORE_PATH ;Restore defaults.
POP AX ;Retrieve error code.
MOV AH,4CH ;Exit.
INT 21H
;***************;
;* SUBROUTINES *;
;***************;
;-----------------------------------------------------------------;
; This subroutine adds the extension COM, EXE and BAT ;
; (in that order) to the filename and checks to see if it exists. ;
;-----------------------------------------------------------------;
CK_EXECUTABLE: MOV DX,OFFSET FILENAME ;Point to filename.
MOV BX,FILENAME_END ;Point to filename end.
MOV SI,OFFSET COM ;Check for .COM
CALL FIND_MATCH
JNC CK_END
MOV SI,OFFSET EXE ;Check for .EXE
CALL FIND_MATCH
JNC CK_END
MOV SI,OFFSET BAT ;Check for .BAT
CALL FIND_MATCH
JC CK_END
MOV BAT_FLAG,1 ;If batch file, indicate so.
CK_END: RET
;---------------------------;
FIND_MATCH: MOV DI,BX ;Add extension to filename.
MOVSW
MOVSW
MOV CX,7
CALL FIND_FIRST ;See if it exists.
RET
;-----------------------------------------------------------------;
; This subroutine executes the file. If it's a batch file, load ;
; secondary copy of COMMAND.COM. Else, let 4Bh execute the file. ;
;-----------------------------------------------------------------;
EXEC: PUSH DS ;Save segment registers.
PUSH ES
CLI
MOV STACK_SEG,SS ;Save stack segment and pointer.
MOV STACK_PTR,SP
STI
MOV COM_LINE_PTR + 2,DS ;Point to command line.
MOV FCB_1ST + 2,DS ;Point to file control blocks.
MOV FCB_2ND + 2,DS
CMP BAT_FLAG,1 ;Is it a batch file?
JNZ EXECUTE ;If no, just execute file.
MOV SI,OFFSET COPY ;Else, let COMMAND.COM/C run it.
MOV DI,OFFSET PARAMETER + 1 ;Construct parameter.
MOVSW
MOVSW
CALL MAKE_FILESPEC ;Add filespec.
DEC DI
CALL ADD_PARAMETER ;Add arguments.
MOV AX,DS:[2CH] ;Retrieve environment segment.
MOV DS,AX
XOR AX,AX
FIND_COMSPEC: MOV SI,AX ;Search for "COMSPEC=".
INC AX
MOV DI,OFFSET COMSPEC
MOV CX,4
REPZ CMPSW
JNZ FIND_COMSPEC
MOV DX,SI ;What follows is COMMAND.COM path.
JMP SHORT EXEC_FILE ;Ready to execute.
EXECUTE: MOV DI,OFFSET FILESPEC ;Construct filespec.
CALL MAKE_FILESPEC
MOV DI,OFFSET PARAMETER + 1 ;Construct arguments.
CALL ADD_PARAMETER
MOV DX,OFFSET FILESPEC
EXEC_FILE: MOV BX,OFFSET PARAMETER_BLOCK ;Point to parameter block.
MOV AX,4B00H ;Execute.
INT 21H
CLI
MOV SP,CS:STACK_PTR ;Restore stack segment and pointer.
MOV SS,CS:STACK_SEG
STI
POP ES ;Restore segment registers.
POP DS
RET
;---------------------------;
MAKE_FILESPEC: CMP CHANGE_FLAG,1 ;Are we to change directory?
JZ ADD_FILENAME ;If yes, execute filename.
MOV AL,WORKING_DISK ;Else, add working drive.
ADD AL,"A"
STOSB
MOV AL,":"
STOSB
MOV SI,DI ;Add working directory.
CALL GET_DIR
CALL RESTORE_PATH ;Restore default path.
MOV DI,SI
CMP BYTE PTR [DI],0 ;If root, ready for filename.
JZ ADD_FILENAME
FIND_END: INC DI ;Else, find end of path.
CMP BYTE PTR [DI],0
JNZ FIND_END
MOV AL,"\" ;Tack on "\" path delimiter.
STOSB
ADD_FILENAME: MOV SI,OFFSET FILENAME ;Add on filename.
NEXT_NAME: LODSB
STOSB
CMP AL,0
JNZ NEXT_NAME
RET
;---------------------------;
ADD_PARAMETER: MOV SI,ARGUMENTS ;Add on arguments.
GET_PARAMETER: LODSB
STOSB
CMP AL,13
JNZ GET_PARAMETER
XOR CL,CL ;Zero in counter.
MOV SI,OFFSET PARAMETER + 1
CNT_PARAMETER: LODSB
CMP AL,13
JZ END_PARAMETER
INC CL ;Count parameter length.
JMP SHORT CNT_PARAMETER
END_PARAMETER: MOV PARAMETER,CL ;Store as first byte of parameter.
RET
;---------------------------------------------;
; This subroutine restores the default paths. ;
;---------------------------------------------;
RESTORE_PATH: CMP WORKING_DISK,0FFH ;Did we get defaults?
JZ END_RESTORE ;If no, done here.
MOV DX,OFFSET WORKING_DIR
CALL CHANGE_DIR
MOV DL,CURRENT_DISK
CALL CHANGE_DRIVE
MOV DX,OFFSET CURRENT_DIR
CALL CHANGE_DIR
END_RESTORE: RET
;----------------------------------------;
; These are the DOS support subroutines. ;
;----------------------------------------;
PRINT_NAME: MOV SI,OFFSET FILENAME ;Print filename
NEXT_PRINT: LODSB
CMP AL,"."
JZ END_NAME
MOV DL,AL
MOV AH,2 ; via DOS Display Output.
INT 21H
JMP SHORT NEXT_PRINT
END_NAME: MOV DX,OFFSET CR_LF ;Print carriage return linefeed.
CALL PRINT_STRING
RET
GET_DRIVE: MOV AH,19H
JMP SHORT DOS_CALL
CHANGE_DRIVE: MOV AH,0EH
JMP SHORT DOS_CALL
FIND_FIRST: MOV AH,4EH
JMP SHORT DOS_CALL
FIND_NEXT: MOV AH,4FH
JMP SHORT DOS_CALL
GET_DIR: MOV BYTE PTR [SI],"\" ;DOS doesn't preface directory
INC SI ; with slash so we must.
XOR DL,DL
MOV AH,47H ;Retrieve default directory.
JMP SHORT DOS_CALL
CHANGE_DIR: MOV AH,3BH
JMP SHORT DOS_CALL
PRINT_STRING: MOV AH,9
JMP SHORT DOS_CALL
CK_KEY: MOV AH,0BH
;---------------------------;
DOS_CALL: INT 21H
RET
;---------------------------------------------------------------;
; This subroutine will systematically change directories up and ;
; down the directory tree, searching for the matching filename. ;
;---------------------------------------------------------------;
GLOBAL_SEARCH: MOV DX,OFFSET SEARCHING ;Display searching message.
CALL PRINT_STRING
CALL PRINT_NAME ;Display filename.
MOV DX,OFFSET ROOT ;Start the search from root.
CALL CHANGE_DIR
MOV DI,OFFSET DIR_LEVEL
MOV BP,DI ;Point to first level directory.
MOV AX,0101H ;Store initial level of one.
MOV CX,64 / 2
REP STOSW
FIRST_FILE: CALL CK_KEY ;Was a key pressed?
CMP AL,0
JNZ END_SEARCHING ;If yes, abort search.
CALL CK_EXECUTABLE ;Check if matching executable.
JC FIRST_DIR ;If no, try next directory.
RET ;Else, return to execute.
PARENT_DIR: CMP BP,OFFSET DIR_LEVEL ;When we try to return to parent
JNZ CONTINUE ; directory and are in root, we
END_SEARCHING: STC ; are done.
RET
CONTINUE: MOV DX,OFFSET PARENT ;Otherwise, change
CALL CHANGE_DIR ; to parent directory.
MOV BYTE PTR DS:[BP],1 ;Put one back in previous level
DEC BP ; and point to parent level.
FIRST_DIR: XOR BL,BL ;Use BL as pointer to directory no.
MOV DX,OFFSET STAR_DOT_STAR
MOV CX,10H ;Ask for directory match.
CALL FIND_FIRST ;Find first matching.
JC PARENT_DIR
CK_DIR: CMP BYTE PTR DS:[DTA+21],10H ;If not a directory, get next.
JNZ NEXT_DIR
CMP BYTE PTR DS:[DTA+30],'.' ;If dot directory, get next.
JZ NEXT_DIR
INC BL ;Increment position in directory.
CMP BL,DS:[BP] ;Continue until new directory.
JNZ NEXT_DIR
INC BYTE PTR DS:[BP] ;Update variables.
MOV DX,OFFSET DTA + 30
CALL CHANGE_DIR ;Change the directory.
INC BP
JMP SHORT FIRST_FILE ;See if directory has a run file.
NEXT_DIR: CALL FIND_NEXT ;Get all subdirectories in current
JC PARENT_DIR ; directory then go to parent.
JMP SHORT CK_DIR
;---------------------------;
PARAMETER LABEL BYTE
FCB_5CH EQU PARAMETER + 256
FCB_6CH EQU FCB_5CH + 16
CURRENT_DIR EQU FCB_6CH + 16
WORKING_DIR EQU CURRENT_DIR + 65
DIR_LEVEL EQU WORKING_DIR + 65
FILENAME EQU DIR_LEVEL + 64
FILESPEC EQU FILENAME + 13
DTA EQU FILESPEC + 67 + 13
CODE_END EQU DTA + 43 + 256
CODE ENDS
END START