mirror of
https://github.com/microsoft/MS-DOS.git
synced 2024-12-01 18:15:47 +00:00
1088 lines
33 KiB
NASM
1088 lines
33 KiB
NASM
TITLE PART1 - COMMAND Transient routines.
|
||
|
||
INCLUDE COMSW.ASM
|
||
|
||
.xlist
|
||
.xcref
|
||
INCLUDE DOSSYM.ASM
|
||
INCLUDE DEVSYM.ASM
|
||
INCLUDE COMSEG.ASM
|
||
.list
|
||
.cref
|
||
|
||
INCLUDE COMEQU.ASM
|
||
|
||
|
||
DATARES SEGMENT PUBLIC
|
||
EXTRN BATCH:WORD,BATLOC:DWORD,PARMBUF:BYTE
|
||
EXTRN RESTDIR:BYTE,EXTCOM:BYTE,ECHOFLAG:BYTE
|
||
EXTRN SINGLECOM:WORD,VERVAL:WORD,FORFLAG:BYTE
|
||
EXTRN RE_INSTR:BYTE,RE_OUT_APP:BYTE,PIPE1:BYTE,PIPE2:BYTE
|
||
EXTRN RE_OUTSTR:BYTE,PIPEFLAG:BYTE,PIPEFILES:BYTE,PIPEPTR:WORD
|
||
EXTRN INPIPEPTR:WORD,OUTPIPEPTR:WORD,EXEC_BLOCK:BYTE,ENVIRSEG:WORD
|
||
DATARES ENDS
|
||
|
||
TRANDATA SEGMENT PUBLIC
|
||
EXTRN BADBAT:BYTE,NEEDBAT:BYTE,BADNAM:BYTE
|
||
EXTRN SYNTMES:BYTE,BADDRV:BYTE,BYTMES_POST:BYTE
|
||
EXTRN DIRMES_PRE:BYTE,DIRMES_POST:BYTE,BYTMES_PRE:BYTE
|
||
EXTRN NOTFND:BYTE,PIPEEMES:BYTE,BADPMES:BYTE,COMTAB:BYTE
|
||
TRANDATA ENDS
|
||
|
||
TRANSPACE SEGMENT PUBLIC
|
||
EXTRN UCOMBUF:BYTE,COMBUF:BYTE,USERDIR1:BYTE,EXECPATH:BYTE
|
||
EXTRN DIRCHAR:BYTE,EXEC_ADDR:DWORD,RCH_ADDR:DWORD,CHKDRV:BYTE
|
||
EXTRN CURDRV:BYTE,PARM1:BYTE,PARM2:BYTE,COMSW:WORD,ARG1S:WORD
|
||
EXTRN ARG2S:WORD,ARGTS:WORD,SPECDRV:BYTE,BYTCNT:WORD,IDLEN:BYTE
|
||
EXTRN DIRBUF:BYTE,ID:BYTE,COM:BYTE,LINCNT:BYTE,INTERNATVARS:BYTE
|
||
EXTRN HEADCALL:DWORD,RESSEG:WORD,TPA:WORD,SWITCHAR:BYTE
|
||
EXTRN STACK:WORD,FILTYP:BYTE,FILECNT:WORD,LINLEN:BYTE
|
||
|
||
|
||
IF KANJI
|
||
EXTRN KPARSE:BYTE
|
||
ENDIF
|
||
TRANSPACE ENDS
|
||
|
||
; ********************************************************************
|
||
; START OF TRANSIENT PORTION
|
||
; This code is loaded at the end of memory and may be overwritten by
|
||
; memory-intensive user programs.
|
||
|
||
TRANCODE SEGMENT PUBLIC PARA
|
||
ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
|
||
|
||
|
||
EXTRN SCANOFF:NEAR,DELIM:NEAR,SAVUDIR:NEAR,SAVUDIR1:NEAR
|
||
EXTRN PATHCHRCMP:NEAR,PRINT:NEAR,RESTUDIR:NEAR
|
||
EXTRN CRLF2:NEAR,PRINT_PROMPT:NEAR,GETBATBYT:NEAR,PRESCAN:NEAR
|
||
EXTRN CRPRINT:NEAR,DISP32BITS:NEAR,FCB_TO_ASCZ:NEAR
|
||
EXTRN ERROR_PRINT:NEAR,FREE_TPA:NEAR,ALLOC_TPA:NEAR
|
||
EXTRN $EXIT:NEAR,FORPROC:NEAR,FIND_NAME_IN_ENVIRONMENT:NEAR
|
||
EXTRN UPCONV:NEAR,BATOPEN:NEAR,BATCLOSE:NEAR,IOSET:NEAR,FIND_PATH:NEAR
|
||
EXTRN TESTDOREIN:NEAR,TESTDOREOUT:NEAR
|
||
|
||
PUBLIC SWLIST,CERROR,SETREST1,DOCOM,DOCOM1,DRVBAD,NOTFNDERR
|
||
PUBLIC COMMAND,TCOMMAND,SWITCH,PIPEERRSYN,GETKEYSTROKE,SETREST
|
||
PUBLIC CHKCNT
|
||
|
||
|
||
IF KANJI
|
||
EXTRN TESTKANJ:NEAR
|
||
ENDIF
|
||
|
||
ORG 0
|
||
ZERO = $
|
||
|
||
ORG 100H ; Allow for 100H parameter area
|
||
|
||
SETDRV:
|
||
MOV AH,SET_DEFAULT_DRIVE
|
||
INT int_command
|
||
TCOMMAND:
|
||
MOV DS,[RESSEG]
|
||
ASSUME DS:RESGROUP
|
||
MOV AX,-1
|
||
XCHG AX,[VERVAL]
|
||
CMP AX,-1
|
||
JZ NOSETVER2
|
||
MOV AH,SET_VERIFY_ON_WRITE ; AL has correct value
|
||
INT int_command
|
||
NOSETVER2:
|
||
CALL [HEADCALL] ; Make sure header fixed
|
||
XOR BP,BP ; Flag transient not read
|
||
CMP [SINGLECOM],-1
|
||
JNZ COMMAND
|
||
$EXITPREP:
|
||
PUSH CS
|
||
POP DS
|
||
JMP $EXIT ; Have finished the single command
|
||
ASSUME DS:NOTHING
|
||
COMMAND:
|
||
CLD
|
||
MOV AX,CS
|
||
MOV SS,AX
|
||
ASSUME SS:TRANGROUP
|
||
MOV SP,OFFSET TRANGROUP:STACK
|
||
MOV ES,AX
|
||
ASSUME ES:TRANGROUP
|
||
MOV DS,[RESSEG]
|
||
ASSUME DS:RESGROUP
|
||
STI
|
||
|
||
MOV [UCOMBUF],COMBUFLEN ; Init UCOMBUF
|
||
MOV [COMBUF],COMBUFLEN ; Init COMBUF (Autoexec doing DATE)
|
||
OR BP,BP ; See if just read
|
||
JZ TESTRDIR ; Not read, check user directory
|
||
MOV WORD PTR [UCOMBUF+1],0D01H ; Reset buffer
|
||
JMP SHORT NOSETBUF
|
||
TESTRDIR:
|
||
CMP [RESTDIR],0
|
||
JZ NOSETBUF ; User directory OK
|
||
PUSH DS
|
||
PUSH CS
|
||
POP DS
|
||
ASSUME DS:TRANGROUP
|
||
MOV DX,OFFSET TRANGROUP:USERDIR1
|
||
MOV AH,CHDIR
|
||
INT int_command ; Restore users directory
|
||
POP DS
|
||
ASSUME DS:RESGROUP
|
||
NOSETBUF:
|
||
CMP [PIPEFILES],0
|
||
JZ NOPCLOSE ; Don't bother if they don't exist
|
||
CMP [PIPEFLAG],0
|
||
JNZ NOPCLOSE ; Don't del if still piping
|
||
CALL PIPEDEL
|
||
NOPCLOSE:
|
||
MOV [EXTCOM],0 ; Flag internal command
|
||
MOV [RESTDIR],0 ; Flag users dirs OK
|
||
MOV AX,CS ; Get segment we're in
|
||
MOV DS,AX
|
||
ASSUME DS:TRANGROUP
|
||
PUSH AX
|
||
MOV DX,OFFSET TRANGROUP:INTERNATVARS
|
||
MOV AX,INTERNATIONAL SHL 8
|
||
INT 21H
|
||
POP AX
|
||
SUB AX,[TPA] ; AX=size of TPA in paragraphs
|
||
MOV DX,16
|
||
MUL DX ; DX:AX=size of TPA in bytes
|
||
OR DX,DX ; See if over 64K
|
||
JZ SAVSIZ ; OK if not
|
||
MOV AX,-1 ; If so, limit to 65535 bytes
|
||
SAVSIZ:
|
||
MOV [BYTCNT],AX ; Max no. of bytes that can be buffered
|
||
MOV DS,[RESSEG] ; All batch work must use resident seg.
|
||
ASSUME DS:RESGROUP
|
||
TEST [ECHOFLAG],-1
|
||
JZ GETCOM ; Don't do the CRLF
|
||
CALL SINGLETEST
|
||
JB GETCOM
|
||
CALL CRLF2
|
||
GETCOM:
|
||
MOV AH,GET_DEFAULT_DRIVE
|
||
INT int_command
|
||
MOV [CURDRV],AL
|
||
TEST [ECHOFLAG],-1
|
||
JZ NOPDRV ; No prompt if echo off
|
||
CALL SINGLETEST
|
||
JB NOPDRV
|
||
CALL PRINT_PROMPT ; Prompt the user
|
||
NOPDRV:
|
||
TEST [PIPEFLAG],-1 ; Pipe has highest presedence
|
||
JZ NOPIPE
|
||
JMP PIPEPROC ; Continue the pipeline
|
||
NOPIPE:
|
||
TEST [FORFLAG],-1 ; FOR has next highest precedence
|
||
JZ TESTFORBAT
|
||
JMP FORPROC ; Continue the FOR
|
||
TESTFORBAT:
|
||
MOV [RE_INSTR],0 ; Turn redirection back off
|
||
MOV [RE_OUTSTR],0
|
||
MOV [RE_OUT_APP],0
|
||
TEST [BATCH],-1 ; Batch has lowest precedence
|
||
JZ ISNOBAT
|
||
JMP READBAT ; Continue BATCH
|
||
|
||
ISNOBAT:
|
||
CMP [SINGLECOM],0
|
||
JZ REGCOM
|
||
MOV SI,-1
|
||
XCHG SI,[SINGLECOM]
|
||
MOV DI,OFFSET TRANGROUP:COMBUF + 2
|
||
XOR CX,CX
|
||
SINGLELOOP:
|
||
LODSB
|
||
STOSB
|
||
INC CX
|
||
CMP AL,0DH
|
||
JNZ SINGLELOOP
|
||
DEC CX
|
||
PUSH CS
|
||
POP DS
|
||
ASSUME DS:TRANGROUP
|
||
MOV [COMBUF + 1],CL
|
||
JMP DOCOM
|
||
|
||
REGCOM:
|
||
PUSH CS
|
||
POP DS ; Need local segment to point to buffer
|
||
MOV DX,OFFSET TRANGROUP:UCOMBUF
|
||
MOV AH,STD_CON_STRING_INPUT
|
||
INT int_command ; Get a command
|
||
MOV CL,[UCOMBUF]
|
||
XOR CH,CH
|
||
ADD CX,3
|
||
MOV SI,OFFSET TRANGROUP:UCOMBUF
|
||
MOV DI,OFFSET TRANGROUP:COMBUF
|
||
REP MOVSB ; Transfer it to the cooked buffer
|
||
JMP DOCOM
|
||
|
||
; All batch proccessing has DS set to segment of resident portion
|
||
ASSUME DS:RESGROUP,ES:TRANGROUP
|
||
|
||
NEEDENV:
|
||
PUSH DS
|
||
PUSH SI
|
||
PUSH DI
|
||
|
||
MOV DI,OFFSET TRANGROUP:ID
|
||
ADD AL,"0"
|
||
STOSB
|
||
GETENV1:
|
||
CALL GETBATBYT
|
||
STOSB
|
||
CMP AL,13
|
||
JZ GETENV2
|
||
CMP AL,"%"
|
||
JNZ GETENV1
|
||
MOV BYTE PTR ES:[DI-1],"="
|
||
GETENV2:
|
||
MOV SI,OFFSET TRANGROUP:ID
|
||
PUSH CS
|
||
POP DS ; DS:SI POINTS TO NAME
|
||
ASSUME DS:TRANGROUP,ES:RESGROUP
|
||
CALL FIND_NAME_IN_environment
|
||
PUSH ES
|
||
POP DS
|
||
PUSH CS
|
||
POP ES
|
||
ASSUME DS:RESGROUP,ES:TRANGROUP
|
||
MOV SI,DI
|
||
POP DI ; get back pointer to command line
|
||
JNC GETENV4
|
||
|
||
GETENV3: ; Parameter not found
|
||
PUSH CS
|
||
POP DS
|
||
MOV SI,OFFSET TRANGROUP:ID
|
||
|
||
GETENV4:
|
||
LODSB ; From resident segment
|
||
OR AL,AL ; Check for end of parameter
|
||
JZ GETENV6
|
||
CMP AL,13
|
||
JZ GETENV6
|
||
CMP AL,"="
|
||
JZ GETENVX
|
||
STOSB
|
||
JMP GETENV4
|
||
|
||
GETENVX:
|
||
MOV AL,"%"
|
||
STOSB
|
||
GETENV6:
|
||
POP SI
|
||
POP DS
|
||
CMP AL,13
|
||
JZ SAVBATBYTJ
|
||
JMP RDBAT
|
||
|
||
NEEDPARM:
|
||
CALL GETBATBYT
|
||
CMP AL,"%" ; Check for two consecutive %
|
||
JZ SAVBATBYTJ
|
||
CMP AL,13 ; Check for end-of-line
|
||
JNZ PAROK
|
||
SAVBATBYTJ:
|
||
JMP SAVBATBYT
|
||
PAROK:
|
||
SUB AL,"0"
|
||
JB NEEDENV ; look for parameter in the environment
|
||
CMP AL,9
|
||
JA NEEDENV
|
||
|
||
CBW
|
||
MOV SI,AX
|
||
SHL SI,1 ; Two bytes per entry
|
||
PUSH ES
|
||
PUSH DI
|
||
MOV ES,[BATCH]
|
||
XOR CX,CX
|
||
MOV AX,CX
|
||
MOV DI,CX
|
||
DEC CX
|
||
REPNZ SCASB
|
||
ADD DI,SI
|
||
MOV SI,ES:[DI]
|
||
POP DI
|
||
POP ES
|
||
CMP SI,-1 ; Check if parameter exists
|
||
JZ RDBAT ; Ignore if it doesn't
|
||
RDPARM:
|
||
LODSB ; From resident segment
|
||
CMP AL,0DH ; Check for end of parameter
|
||
JZ RDBAT
|
||
STOSB
|
||
JMP RDPARM
|
||
|
||
PROMPTBAT:
|
||
MOV DX,OFFSET TRANGROUP:NEEDBAT
|
||
CALL [RCH_ADDR]
|
||
JZ AskForBat ; Media is removable
|
||
NoAskForBat:
|
||
MOV ES,[BATCH] ; Turn off batch
|
||
MOV AH,DEALLOC
|
||
INT int_command ; free up the batch piece
|
||
MOV [BATCH],0 ; AFTER DEALLOC in case of ^C
|
||
MOV [FORFLAG],0 ; Turn off for processing
|
||
MOV [PIPEFLAG],0 ; Turn off any pipe
|
||
PUSH CS
|
||
POP DS
|
||
MOV DX,OFFSET TRANGROUP:BADBAT
|
||
CALL ERROR_PRINT ; Tell user no batch file
|
||
JMP TCOMMAND
|
||
|
||
ASKFORBAT:
|
||
PUSH CS
|
||
POP DS
|
||
CALL ERROR_PRINT ; Prompt for batch file
|
||
CALL GetKeystroke
|
||
JMP TCOMMAND
|
||
;**************************************************************************
|
||
; read the next keystroke
|
||
|
||
GetKeystroke:
|
||
MOV AX,(STD_CON_INPUT_FLUSH SHL 8) OR STD_CON_INPUT_no_echo
|
||
INT int_command ; Get character with KB buffer flush
|
||
MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0
|
||
INT int_command
|
||
return
|
||
|
||
READBAT:
|
||
CALL BATOPEN
|
||
JC PROMPTBAT
|
||
MOV DI,OFFSET TRANGROUP:COMBUF+2
|
||
TESTNOP:
|
||
CALL GETBATBYT
|
||
CMP AL,':' ; Label/Comment?
|
||
JNZ NOTLABEL
|
||
NOPLINE: ; Consume the line
|
||
CALL GETBATBYT
|
||
CMP AL,0DH
|
||
JNZ NOPLINE
|
||
CALL GETBATBYT ; Eat Linefeed
|
||
TEST [BATCH],-1
|
||
JNZ TESTNOP
|
||
JMP TCOMMAND ; Hit EOF
|
||
|
||
RDBAT:
|
||
CALL GETBATBYT
|
||
NOTLABEL:
|
||
CMP AL,"%" ; Check for parameter
|
||
JNZ SAVBATBYT
|
||
JMP NEEDPARM
|
||
SAVBATBYT:
|
||
STOSB
|
||
CMP AL,0DH
|
||
JNZ RDBAT
|
||
SUB DI,OFFSET TRANGROUP:COMBUF+3
|
||
MOV AX,DI
|
||
MOV ES:[COMBUF+1],AL ; Set length of line
|
||
CALL GETBATBYT ; Eat linefeed
|
||
CALL BATCLOSE
|
||
TEST [ECHOFLAG],-1
|
||
PUSH CS
|
||
POP DS ; Go back to local segment
|
||
JZ NOECHO2
|
||
ASSUME DS:TRANGROUP
|
||
MOV DX,OFFSET TRANGROUP:COMBUF+2
|
||
CALL CRPRINT
|
||
DOCOM:
|
||
; All segments are local for command line processing
|
||
CALL CRLF2
|
||
DOCOM1:
|
||
|
||
NOECHO2:
|
||
CALL PRESCAN ; Cook the input buffer
|
||
JZ NOPIPEPROC
|
||
JMP PIPEPROCSTRT ; Fire up the pipe
|
||
NOPIPEPROC:
|
||
MOV SI,OFFSET TRANGROUP:COMBUF+2
|
||
MOV DI,OFFSET TRANGROUP:IDLEN
|
||
MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H ; Make FCB with blank scan-off
|
||
INT int_command
|
||
CMP AL,1 ; Check for ambiguous command name
|
||
JZ BADCOMJ1 ; Ambiguous commands not allowed
|
||
CMP AL,-1
|
||
JNZ DRVGD
|
||
JMP DRVBAD
|
||
|
||
BADCOMJ1:
|
||
JMP BADCOM
|
||
|
||
DRVGD:
|
||
MOV AL,[DI]
|
||
MOV [SPECDRV],AL
|
||
MOV AL," "
|
||
MOV CX,9
|
||
INC DI
|
||
REPNE SCASB ; Count no. of letters in command name
|
||
MOV AL,9
|
||
SUB AL,CL
|
||
MOV [IDLEN],AL
|
||
MOV DI,81H
|
||
XOR CX,CX
|
||
PUSH SI
|
||
COMTAIL:
|
||
LODSB
|
||
STOSB ; Move command tail to 80H
|
||
CMP AL,13
|
||
LOOPNZ COMTAIL
|
||
NOT CL
|
||
MOV BYTE PTR DS:[80H],CL
|
||
POP SI
|
||
; If the command has 0 parameters must check here for
|
||
; any switches that might be present.
|
||
; SI -> first character after the command.
|
||
CALL SWITCH ; Is the next character a SWITCHAR
|
||
MOV [COMSW],AX
|
||
MOV DI,FCB
|
||
MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H
|
||
INT int_command
|
||
MOV [PARM1],AL ; Save result of parse
|
||
|
||
PRBEG:
|
||
LODSB
|
||
CMP AL,[SWITCHAR]
|
||
JZ PRFIN
|
||
CMP AL,13
|
||
JZ PRFIN
|
||
CALL DELIM
|
||
JNZ PRBEG
|
||
PRFIN:
|
||
DEC SI
|
||
CALL SWITCH
|
||
MOV [ARG1S],AX
|
||
MOV DI,FCB+10H
|
||
MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H
|
||
INT int_command ; Parse file name
|
||
MOV [PARM2],AL ; Save result
|
||
CALL SWITCH
|
||
MOV [ARG2S],AX
|
||
OR AX,[ARG1S]
|
||
MOV [ARGTS],AX
|
||
SWTLP: ; Find any remaining switches
|
||
CMP BYTE PTR [SI],0DH
|
||
JZ GOTALLSW
|
||
INC SI
|
||
CALL SWITCH
|
||
OR [ARGTS],AX
|
||
JMP SHORT SWTLP
|
||
|
||
GOTALLSW:
|
||
MOV AL,[IDLEN]
|
||
MOV DL,[SPECDRV]
|
||
OR DL,DL ; Check if drive was specified
|
||
JZ OK
|
||
JMP DRVCHK
|
||
OK:
|
||
DEC AL ; Check for null command
|
||
JNZ FNDCOM
|
||
MOV DS,[RESSEG]
|
||
ASSUME DS:RESGROUP
|
||
CMP [SINGLECOM],-1
|
||
JZ EXITJ
|
||
JMP GETCOM
|
||
|
||
EXITJ:
|
||
JMP $EXITPREP
|
||
ASSUME DS:TRANGROUP
|
||
|
||
RETSW:
|
||
XCHG AX,BX ; Put switches in AX
|
||
return
|
||
|
||
SWITCH:
|
||
XOR BX,BX ; Initialize - no switches set
|
||
SWLOOP:
|
||
CALL SCANOFF ; Skip any delimiters
|
||
CMP AL,[SWITCHAR] ; Is it a switch specifier?
|
||
JNZ RETSW ; No -- we're finished
|
||
OR BX,GOTSWITCH ; Indicate there is a switch specified
|
||
INC SI ; Skip over the switch character
|
||
CALL SCANOFF
|
||
CMP AL,0DH
|
||
JZ RETSW ; Oops
|
||
INC SI
|
||
; Convert lower case input to upper case
|
||
CALL UPCONV
|
||
MOV DI,OFFSET TRANGROUP:SWLIST
|
||
MOV CX,SWCOUNT
|
||
REPNE SCASB ; Look for matching switch
|
||
JNZ BADSW
|
||
MOV AX,1
|
||
SHL AX,CL ; Set a bit for the switch
|
||
OR BX,AX
|
||
JMP SHORT SWLOOP
|
||
|
||
BADSW:
|
||
JMP SHORT SWLOOP
|
||
|
||
SWLIST DB "VBAPW"
|
||
SWCOUNT EQU $-SWLIST
|
||
|
||
DRVBAD:
|
||
MOV DX,OFFSET TRANGROUP:BADDRV
|
||
JMP CERROR
|
||
|
||
FNDCOM:
|
||
MOV SI,OFFSET TRANGROUP:COMTAB ; Prepare to search command table
|
||
MOV CH,0
|
||
FINDCOM:
|
||
MOV DI,OFFSET TRANGROUP:IDLEN
|
||
MOV CL,[SI]
|
||
JCXZ EXTERNAL
|
||
REPE CMPSB
|
||
LAHF
|
||
ADD SI,CX ; Bump to next position without affecting flags
|
||
SAHF
|
||
LODSB ; Get flag for drive check
|
||
MOV [CHKDRV],AL
|
||
LODSW ; Get address of command
|
||
JNZ FINDCOM
|
||
MOV DX,AX
|
||
CMP [CHKDRV],0
|
||
JZ NOCHECK
|
||
MOV AL,[PARM1]
|
||
OR AL,[PARM2] ; Check if either parm. had invalid drive
|
||
CMP AL,-1
|
||
JZ DRVBAD
|
||
NOCHECK:
|
||
CALL IOSET
|
||
CALL DX ; Call the internal
|
||
COMJMP:
|
||
JMP TCOMMAND
|
||
|
||
SETDRV1:
|
||
JMP SETDRV
|
||
|
||
DRVCHK:
|
||
DEC DL ; Adjust for correct drive number
|
||
DEC AL ; Check if anything else is on line
|
||
JZ SETDRV1
|
||
EXTERNAL:
|
||
MOV [FILTYP],0
|
||
MOV DL,[SPECDRV]
|
||
MOV [IDLEN],DL
|
||
CALL SAVUDIR ; Drive letter already checked
|
||
MOV AL,'?'
|
||
MOV DI,OFFSET TRANGROUP:COM
|
||
STOSB ; Look for any extension
|
||
STOSB
|
||
STOSB
|
||
MOV DX,OFFSET TRANGROUP:DIRBUF ; Command will end up here
|
||
MOV AH,SET_DMA
|
||
INT int_command
|
||
PUSH ES
|
||
CALL FIND_PATH
|
||
MOV SI,DI
|
||
POP ES
|
||
|
||
MOV DI,OFFSET TRANGROUP:EXECPATH
|
||
MOV BYTE PTR [DI],0 ; Initialize to current directory
|
||
RESEARCH:
|
||
MOV AH,DIR_SEARCH_FIRST
|
||
COMSRCH:
|
||
PUSH CS
|
||
POP DS
|
||
MOV DX,OFFSET TRANGROUP:IDLEN
|
||
INT int_command
|
||
OR AL,AL
|
||
MOV AH,DIR_SEARCH_NEXT ; Do search-next next
|
||
JNZ PATHCHK
|
||
CMP WORD PTR [DIRBUF+9],4F00H + "C"
|
||
JNZ CHKEXE
|
||
CMP [DIRBUF+11],"M"
|
||
JNZ CHKEXE
|
||
OR [FILTYP],4
|
||
JMP EXECUTE ; If we find a COM were done
|
||
|
||
CHKEXE:
|
||
CMP WORD PTR [DIRBUF+9],5800H + "E"
|
||
JNZ CHKBAT
|
||
CMP [DIRBUF+11],"E"
|
||
JNZ CHKBAT
|
||
OR [FILTYP],1 ; Flag an EXE found
|
||
JMP COMSRCH ; Continue search
|
||
|
||
CHKBAT:
|
||
CMP WORD PTR [DIRBUF+9],4100H + "B"
|
||
JNZ COMSRCH
|
||
CMP [DIRBUF+11],"T"
|
||
JNZ COMSRCH
|
||
OR [FILTYP],2 ; Flag BAT found
|
||
JMP COMSRCH ; Continue search
|
||
|
||
PATHCHK:
|
||
TEST [FILTYP],1
|
||
JZ TESTBAT
|
||
MOV WORD PTR [DIRBUF+9],5800H+"E"
|
||
MOV [DIRBUF+11],"E"
|
||
JMP EXECUTE ; Found EXE
|
||
|
||
TESTBAT:
|
||
TEST [FILTYP],2
|
||
JZ NEXTPATH ; Found nothing, try next path
|
||
MOV WORD PTR [DIRBUF+9],4100H+"B"
|
||
MOV [DIRBUF+11],"T"
|
||
MOV DX,OFFSET TRANGROUP:DIRBUF ; Found BAT
|
||
MOV AH,FCB_OPEN
|
||
INT int_command
|
||
OR AL,AL
|
||
JZ BATCOMJ ; Bat exists
|
||
CALL RESTUDIR
|
||
JMP BADCOM
|
||
|
||
BATCOMJ:
|
||
JMP BATCOM
|
||
|
||
NEXTPATH:
|
||
MOV DX,OFFSET TRANGROUP:USERDIR1 ; Restore users dir
|
||
MOV AH,CHDIR
|
||
INT int_command
|
||
MOV DS,[RESSEG]
|
||
ASSUME DS:RESGROUP
|
||
MOV [RESTDIR],0
|
||
BADPATHEL:
|
||
MOV DI,OFFSET TRANGROUP:EXECPATH ; Build a full path here
|
||
MOV DX,SI
|
||
MOV DS,[ENVIRSEG] ; Point into environment
|
||
ASSUME DS:NOTHING
|
||
LODSB
|
||
|
||
IF KANJI
|
||
MOV [KPARSE],0
|
||
ENDIF
|
||
|
||
OR AL,AL
|
||
JZ BADCOMJ ; NUL, command not found
|
||
XOR BL,BL ; Make BL a NUL
|
||
PSKIPLP: ; Get the path
|
||
STOSB
|
||
OR AL,AL
|
||
JZ LASTPATH
|
||
CMP AL,';'
|
||
JZ GOTNEXTPATH
|
||
CMP DI,15+DirStrLen+(OFFSET TRANGROUP:EXECPATH)
|
||
JB OKPath
|
||
SKIPPathElem:
|
||
LODSB ; scan to end of path element
|
||
OR AL,AL
|
||
JZ BadPathEl
|
||
CMP AL,';'
|
||
JZ BadPathEl
|
||
JMP SkipPathElem
|
||
|
||
OKPath:
|
||
IF KANJI
|
||
MOV [KPARSE],0
|
||
CALL TESTKANJ
|
||
JZ NXTPTCHR
|
||
INC [KPARSE]
|
||
MOVSB
|
||
NXTPTCHR:
|
||
ENDIF
|
||
|
||
LODSB
|
||
JMP SHORT PSKIPLP
|
||
|
||
BADCOMJ:
|
||
JMP BADCOM
|
||
|
||
LASTPATH:
|
||
MOV BYTE PTR ES:[DI-1],';' ; Fix up the NUL in EXECPATH
|
||
DEC SI ; Point to the NUL in PATHSTRING
|
||
MOV BL,[SI-1] ; Change substi char to char before NUL
|
||
|
||
GOTNEXTPATH:
|
||
DEC DI ; Point to the end of the dir
|
||
PUSH BX
|
||
PUSH SI
|
||
PUSH DX
|
||
MOV SI,DX
|
||
XOR DL,DL
|
||
CMP BYTE PTR [SI+1],DRVCHAR
|
||
JNZ DEFDRVPATH ; No drive spec
|
||
MOV DL,[SI]
|
||
SUB DL,'@'
|
||
DEFDRVPATH:
|
||
PUSH DS
|
||
PUSH CS
|
||
POP DS
|
||
ASSUME DS:TRANGROUP
|
||
MOV [IDLEN],DL ; New drive
|
||
PUSH DI
|
||
CALL SAVUDIR ; Save the users dir
|
||
POP DI
|
||
JNC PATHTRY
|
||
MOV DX,OFFSET TRANGROUP:BADPMES ; Tell the user bad stuff in path
|
||
CALL PRINT
|
||
PATHTRY:
|
||
POP DS
|
||
ASSUME DS:NOTHING
|
||
POP DX
|
||
POP SI
|
||
POP BX
|
||
XCHG BL,[SI-1] ; Stick in NUL, or same thing if LASTPATH
|
||
CDPATH:
|
||
MOV AH,CHDIR
|
||
INT int_command
|
||
MOV [SI-1],BL ; Fix the path string back up
|
||
MOV DS,[RESSEG]
|
||
ASSUME DS:RESGROUP
|
||
INC [RESTDIR] ; Say users dir needs restoring
|
||
JNC ResearchJ
|
||
JMP BADPATHEL ; Ignore a directory which doesn't exist
|
||
ResearchJ:
|
||
JMP RESEARCH ; Try looking in this one
|
||
|
||
BATCOM:
|
||
ASSUME DS:TRANGROUP
|
||
; Batch parameters are read with ES set to segment of resident part
|
||
CALL IOSET ; Set up any redirection
|
||
MOV ES,[RESSEG]
|
||
ASSUME ES:RESGROUP
|
||
;Since BATCH has lower precedence than PIPE or FOR. If a new BATCH file
|
||
;is being started it MUST be true that no FOR or PIPE is currently in
|
||
;progress.
|
||
MOV [FORFLAG],0 ; Turn off for processing
|
||
MOV [PIPEFLAG],0 ; Turn off any pipe
|
||
TEST [BATCH],-1
|
||
JNZ CHAINBAT ; Don't need allocation if chaining
|
||
CALL FREE_TPA
|
||
ASSUME ES:RESGROUP
|
||
MOV BX,6 ; 64 + 32 bytes
|
||
MOV AH,ALLOC
|
||
INT int_command ; Suck up a little piece for batch processing
|
||
MOV [BATCH],AX
|
||
CALL ALLOC_TPA
|
||
CHAINBAT:
|
||
PUSH ES
|
||
MOV ES,[BATCH]
|
||
ASSUME ES:NOTHING
|
||
MOV DL,[DIRBUF]
|
||
XOR DI,DI
|
||
CALL SAVUDIR1 ; ES:DI set up, get dir containing Batch file
|
||
XOR AX,AX
|
||
MOV CX,AX
|
||
DEC CX
|
||
REPNZ SCASB ; Find the NUL
|
||
DEC DI ; Point at the NUL
|
||
MOV AL,[DIRCHAR]
|
||
CMP AL,ES:[DI-1]
|
||
JZ NOPUTSLASH
|
||
STOSB
|
||
NOPUTSLASH:
|
||
MOV SI,OFFSET TRANGROUP:DIRBUF+1
|
||
CALL FCB_TO_ASCZ ; Tack on batch file name
|
||
MOV AX,-1
|
||
MOV BX,DI
|
||
MOV CX,10
|
||
REP STOSW ; Init Parmtab to no parms
|
||
POP ES
|
||
ASSUME ES:RESGROUP
|
||
CALL RESTUDIR
|
||
MOV SI,OFFSET TRANGROUP:COMBUF+2
|
||
MOV DI,OFFSET RESGROUP:PARMBUF
|
||
MOV CX,10
|
||
EACHPARM:
|
||
CALL SCANOFF
|
||
CMP AL,0DH
|
||
JZ HAVPARM
|
||
JCXZ MOVPARM ; Only first 10 parms get pointers
|
||
PUSH ES
|
||
MOV ES,[BATCH]
|
||
MOV ES:[BX],DI ; Set pointer table to point to actual parameter
|
||
POP ES
|
||
INC BX
|
||
INC BX
|
||
MOVPARM:
|
||
LODSB
|
||
CALL DELIM
|
||
JZ ENDPARM ; Check for end of parameter
|
||
STOSB
|
||
CMP AL,0DH
|
||
JZ HAVPARM
|
||
JMP SHORT MOVPARM
|
||
ENDPARM:
|
||
MOV AL,0DH
|
||
STOSB ; End-of-parameter marker
|
||
JCXZ EACHPARM
|
||
DEC CX
|
||
JMP SHORT EACHPARM
|
||
HAVPARM:
|
||
XOR AL,AL
|
||
STOSB ; Nul terminate the parms
|
||
XOR AX,AX
|
||
PUSH ES
|
||
POP DS ; Simply batch FCB setup
|
||
ASSUME DS:RESGROUP
|
||
MOV WORD PTR [BATLOC],AX ; Start at beginning of file
|
||
MOV WORD PTR [BATLOC+2],AX
|
||
CMP [SINGLECOM],-1
|
||
JNZ NOBATSING
|
||
MOV [SINGLECOM],0FFF0H ; Flag single command BATCH job
|
||
NOBATSING:
|
||
JMP TCOMMAND
|
||
ASSUME DS:TRANGROUP,ES:TRANGROUP
|
||
|
||
EXECUTE:
|
||
CALL RESTUDIR
|
||
NeoExecute:
|
||
CMP BYTE PTR [DI],0 ; Command in current directory
|
||
JZ NNSLSH
|
||
MOV AL,[DI-1]
|
||
|
||
IF KANJI
|
||
CMP [KPARSE],0
|
||
JNZ StuffPath ; Last char is second KANJI byte, might be '\'
|
||
ENDIF
|
||
|
||
CALL PATHCHRCMP
|
||
JZ HAVEXP ; Don't double slash
|
||
StuffPath:
|
||
MOV AL,[DIRCHAR]
|
||
STOSB
|
||
JMP SHORT HAVEXP
|
||
|
||
NNSLSH:
|
||
MOV AL,[DIRBUF] ; Specify a drive
|
||
ADD AL,'@'
|
||
STOSB
|
||
MOV AL,DRVCHAR
|
||
STOSB
|
||
HAVEXP:
|
||
MOV SI,OFFSET TRANGROUP:DIRBUF+1
|
||
CALL FCB_TO_ASCZ ; Tack on the filename
|
||
CALL IOSET
|
||
MOV ES,[TPA]
|
||
MOV AH,DEALLOC
|
||
INT int_command ; Now running in "free" space
|
||
MOV ES,[RESSEG]
|
||
ASSUME ES:RESGROUP
|
||
INC [EXTCOM] ; Indicate external command
|
||
MOV [RESTDIR],0 ; Since USERDIR1 is in transient, insure
|
||
; this flag value for re-entry to COMMAND
|
||
MOV DI,FCB
|
||
MOV SI,DI
|
||
MOV CX,052H
|
||
REP MOVSW ; Transfer parameters to resident header
|
||
MOV DX,OFFSET TRANGROUP:EXECPATH
|
||
MOV BX,OFFSET RESGROUP:EXEC_BLOCK
|
||
MOV AX,EXEC SHL 8
|
||
JMP [EXEC_ADDR] ; Jmp to the EXEC in the resident
|
||
|
||
BADCOM:
|
||
PUSH CS
|
||
POP DS
|
||
MOV DX,OFFSET TRANGROUP:BADNAM
|
||
CERROR:
|
||
CALL ERROR_PRINT
|
||
JMP TCOMMAND
|
||
|
||
SINGLETEST:
|
||
ASSUME DS:RESGROUP
|
||
CMP [SINGLECOM],0
|
||
JZ RET5
|
||
CMP [SINGLECOM],0EFFFH
|
||
return
|
||
|
||
|
||
ASSUME DS:TRANGROUP
|
||
SETREST1:
|
||
MOV AL,1
|
||
SETREST:
|
||
PUSH DS
|
||
MOV DS,[RESSEG]
|
||
ASSUME DS:RESGROUP
|
||
MOV [RESTDIR],AL
|
||
POP DS
|
||
ASSUME DS:TRANGROUP
|
||
RET5:
|
||
return
|
||
|
||
CHKCNT:
|
||
TEST [FILECNT],-1
|
||
JNZ ENDDIR
|
||
NOTFNDERR:
|
||
MOV DX,OFFSET TRANGROUP:NOTFND
|
||
JMP CERROR
|
||
|
||
ENDDIR:
|
||
; Make sure last line ends with CR/LF
|
||
MOV AL,[LINLEN]
|
||
CMP AL,[LINCNT] ; Will be equal if just had CR/LF
|
||
JZ MESSAGE
|
||
CALL CRLF2
|
||
MESSAGE:
|
||
MOV DX,OFFSET TRANGROUP:DIRMES_PRE
|
||
CALL PRINT
|
||
MOV SI,[FILECNT]
|
||
XOR DI,DI
|
||
CALL DISP32BITS
|
||
MOV DX,OFFSET TRANGROUP:DIRMES_POST
|
||
CALL PRINT
|
||
MOV AH,GET_DRIVE_FREESPACE
|
||
MOV DL,BYTE PTR DS:[FCB]
|
||
INT int_command
|
||
CMP AX,-1
|
||
retz
|
||
MOV DX,OFFSET TRANGROUP:BYTMES_PRE
|
||
CALL PRINT
|
||
MUL CX ; AX is bytes per cluster
|
||
MUL BX
|
||
MOV DI,DX
|
||
MOV SI,AX
|
||
CALL DISP32BITS
|
||
MOV DX,OFFSET TRANGROUP:BYTMES_POST
|
||
JMP PRINT
|
||
|
||
ASSUME DS:RESGROUP
|
||
|
||
PIPEDEL:
|
||
PUSH DX
|
||
MOV DX,OFFSET RESGROUP:PIPE1 ; Clean up in case ^C
|
||
MOV AH,UNLINK
|
||
INT int_command
|
||
MOV DX,OFFSET RESGROUP:PIPE2
|
||
MOV AH,UNLINK
|
||
INT int_command
|
||
XOR AX,AX
|
||
MOV WORD PTR [PIPEFLAG],AX ; Pipe files and pipe gone
|
||
MOV [ECHOFLAG],1 ; Make sure ^C to pipe doesn't leave ECHO OFF
|
||
POP DX
|
||
return
|
||
|
||
PIPEERRSYN:
|
||
MOV DX,OFFSET TRANGROUP:SYNTMES
|
||
JMP SHORT PIPPERR
|
||
PIPEERR:
|
||
MOV DX,OFFSET TRANGROUP:PIPEEMES
|
||
PIPPERR:
|
||
CALL PIPEDEL
|
||
PUSH CS
|
||
POP DS
|
||
JMP CERROR
|
||
|
||
PIPEPROCSTRT:
|
||
ASSUME DS:TRANGROUP,ES:TRANGROUP
|
||
MOV DS,[RESSEG]
|
||
ASSUME DS:RESGROUP
|
||
INC [PIPEFILES] ; Flag that the pipe files exist
|
||
MOV AH,19H ; Get current drive
|
||
INT int_command
|
||
ADD AL,'A'
|
||
MOV [PIPE2],AL ; Make pipe files in root of def drv
|
||
MOV BX,OFFSET RESGROUP:PIPE1
|
||
MOV [BX],AL
|
||
MOV DX,BX
|
||
XOR CX,CX
|
||
MOV AH,CREAT
|
||
INT int_command
|
||
JC PIPEERR ; Couldn't create
|
||
MOV BX,AX
|
||
MOV AH,CLOSE ; Don't proliferate handles
|
||
INT int_command
|
||
MOV DX,OFFSET RESGROUP:PIPE2
|
||
MOV AH,CREAT
|
||
INT int_command
|
||
JC PIPEERR
|
||
MOV BX,AX
|
||
MOV AH,CLOSE
|
||
INT int_command
|
||
CALL TESTDOREIN ; Set up a redirection if specified
|
||
MOV [ECHOFLAG],0 ; No echo on pipes
|
||
MOV SI,[PIPEPTR]
|
||
CMP [SINGLECOM],-1
|
||
JNZ NOSINGP
|
||
MOV [SINGLECOM],0F000H ; Flag single command pipe
|
||
NOSINGP:
|
||
JMP SHORT FIRSTPIPE
|
||
|
||
PIPEPROC:
|
||
ASSUME DS:RESGROUP
|
||
MOV [ECHOFLAG],0 ; No echo on pipes
|
||
MOV SI,[PIPEPTR]
|
||
LODSB
|
||
CMP AL,'|'
|
||
JNZ PIPEEND ; Pipe done
|
||
MOV DX,[INPIPEPTR] ; Get the input file name
|
||
MOV AX,(OPEN SHL 8)
|
||
INT int_command
|
||
PIPEERRJ:
|
||
JC PIPEERR ; Lost the pipe file
|
||
MOV BX,AX
|
||
MOV AL,0FFH
|
||
XCHG AL,[BX.PDB_JFN_Table]
|
||
MOV DS:[PDB_JFN_Table],AL ; Redirect
|
||
FIRSTPIPE:
|
||
MOV DI,OFFSET TRANGROUP:COMBUF + 2
|
||
XOR CX,CX
|
||
CMP BYTE PTR [SI],0DH ; '|<CR>'
|
||
JNZ PIPEOK1
|
||
PIPEERRSYNJ:
|
||
JMP PIPEERRSYN
|
||
PIPEOK1:
|
||
CMP BYTE PTR [SI],'|' ; '||'
|
||
JZ PIPEERRSYNJ
|
||
PIPECOMLP:
|
||
LODSB
|
||
STOSB
|
||
|
||
IF KANJI
|
||
CALL TESTKANJ
|
||
JZ NOTKANJ5
|
||
MOVSB
|
||
JMP PIPECOMLP
|
||
|
||
NOTKANJ5:
|
||
ENDIF
|
||
|
||
CMP AL,0DH
|
||
JZ LASTPIPE
|
||
INC CX
|
||
CMP AL,'|'
|
||
JNZ PIPECOMLP
|
||
MOV BYTE PTR ES:[DI-1],0DH
|
||
DEC CX
|
||
MOV [COMBUF+1],CL
|
||
DEC SI
|
||
MOV [PIPEPTR],SI ; On to next pipe element
|
||
MOV DX,[OUTPIPEPTR]
|
||
PUSH CX
|
||
XOR CX,CX
|
||
MOV AX,(CREAT SHL 8)
|
||
INT int_command
|
||
POP CX
|
||
JC PIPEERRJ ; Lost the file
|
||
MOV BX,AX
|
||
MOV AL,0FFH
|
||
XCHG AL,[BX.PDB_JFN_Table]
|
||
MOV DS:[PDB_JFN_Table+1],AL
|
||
XCHG DX,[INPIPEPTR] ; Swap for next element of pipe
|
||
MOV [OUTPIPEPTR],DX
|
||
JMP SHORT PIPECOM
|
||
|
||
LASTPIPE:
|
||
MOV [COMBUF+1],CL
|
||
DEC SI
|
||
MOV [PIPEPTR],SI ; Point at the CR (anything not '|' will do)
|
||
CALL TESTDOREOUT ; Set up the redirection if specified
|
||
PIPECOM:
|
||
PUSH CS
|
||
POP DS
|
||
JMP NOPIPEPROC ; Process the pipe element
|
||
|
||
PIPEEND:
|
||
CALL PIPEDEL
|
||
CMP [SINGLECOM],0F000H
|
||
JNZ NOSINGP2
|
||
MOV [SINGLECOM],-1 ; Make it return
|
||
NOSINGP2:
|
||
JMP TCOMMAND
|
||
|
||
TRANCODE ENDS
|
||
END
|
||
|