1 TITLE PART1
- COMMAND Transient routines
.
16 DATARES
SEGMENT PUBLIC
17 EXTRN BATCH
:WORD,BATLOC
:DWORD,PARMBUF
:BYTE
18 EXTRN RESTDIR
:BYTE,EXTCOM
:BYTE,ECHOFLAG
:BYTE
19 EXTRN SINGLECOM
:WORD,VERVAL
:WORD,FORFLAG
:BYTE
20 EXTRN RE_INSTR
:BYTE,RE_OUT_APP
:BYTE,PIPE1
:BYTE,PIPE2
:BYTE
21 EXTRN RE_OUTSTR
:BYTE,PIPEFLAG
:BYTE,PIPEFILES
:BYTE,PIPEPTR
:WORD
22 EXTRN INPIPEPTR
:WORD,OUTPIPEPTR
:WORD,EXEC_BLOCK
:BYTE,ENVIRSEG
:WORD
25 TRANDATA
SEGMENT PUBLIC
26 EXTRN BADBAT
:BYTE,NEEDBAT
:BYTE,BADNAM
:BYTE
27 EXTRN SYNTMES
:BYTE,BADDRV
:BYTE,BYTMES_POST
:BYTE
28 EXTRN DIRMES_PRE
:BYTE,DIRMES_POST
:BYTE,BYTMES_PRE
:BYTE
29 EXTRN NOTFND
:BYTE,PIPEEMES
:BYTE,BADPMES
:BYTE,COMTAB
:BYTE
32 TRANSPACE
SEGMENT PUBLIC
33 EXTRN UCOMBUF
:BYTE,COMBUF
:BYTE,USERDIR1
:BYTE,EXECPATH
:BYTE
34 EXTRN DIRCHAR
:BYTE,EXEC_ADDR
:DWORD,RCH_ADDR
:DWORD,CHKDRV
:BYTE
35 EXTRN CURDRV
:BYTE,PARM1
:BYTE,PARM2
:BYTE,COMSW
:WORD,ARG1S
:WORD
36 EXTRN ARG2S
:WORD,ARGTS
:WORD,SPECDRV
:BYTE,BYTCNT
:WORD,IDLEN
:BYTE
37 EXTRN DIRBUF
:BYTE,ID
:BYTE,COM
:BYTE,LINCNT
:BYTE,INTERNATVARS
:BYTE
38 EXTRN HEADCALL
:DWORD,RESSEG
:WORD,TPA
:WORD,SWITCHAR
:BYTE
39 EXTRN STACK:WORD,FILTYP
:BYTE,FILECNT
:WORD,LINLEN
:BYTE
47 ; ********************************************************************
48 ; START OF TRANSIENT PORTION
49 ; This code is loaded at the end of memory and may be overwritten by
50 ; memory-intensive user programs.
52 TRANCODE
SEGMENT PUBLIC PARA
53 ASSUME
CS:TRANGROUP
,DS:NOTHING
,ES:NOTHING
,SS:NOTHING
56 EXTRN SCANOFF
:NEAR,DELIM
:NEAR,SAVUDIR
:NEAR,SAVUDIR1
:NEAR
57 EXTRN PATHCHRCMP
:NEAR,PRINT
:NEAR,RESTUDIR
:NEAR
58 EXTRN CRLF2
:NEAR,PRINT_PROMPT
:NEAR,GETBATBYT
:NEAR,PRESCAN
:NEAR
59 EXTRN CRPRINT
:NEAR,DISP32BITS
:NEAR,FCB_TO_ASCZ
:NEAR
60 EXTRN ERROR_PRINT
:NEAR,FREE_TPA
:NEAR,ALLOC_TPA
:NEAR
61 EXTRN $EXIT
:NEAR,FORPROC
:NEAR,FIND_NAME_IN_ENVIRONMENT
:NEAR
62 EXTRN UPCONV
:NEAR,BATOPEN
:NEAR,BATCLOSE
:NEAR,IOSET
:NEAR,FIND_PATH
:NEAR
63 EXTRN TESTDOREIN
:NEAR,TESTDOREOUT
:NEAR
65 PUBLIC SWLIST
,CERROR
,SETREST1
,DOCOM
,DOCOM1
,DRVBAD
,NOTFNDERR
66 PUBLIC COMMAND
,TCOMMAND
,SWITCH
,PIPEERRSYN
,GETKEYSTROKE
,SETREST
77 ORG 100H
; Allow for 100H parameter area
80 MOV AH,SET_DEFAULT_DRIVE
89 MOV AH,SET_VERIFY_ON_WRITE
; AL has correct value
92 CALL [HEADCALL
] ; Make sure header fixed
93 XOR BP,BP ; Flag transient not read
99 JMP $EXIT
; Have finished the single command
106 MOV SP,OFFSET TRANGROUP
:STACK
113 MOV [UCOMBUF
],COMBUFLEN
; Init UCOMBUF
114 MOV [COMBUF
],COMBUFLEN
; Init COMBUF (Autoexec doing DATE)
115 OR BP,BP ; See if just read
116 JZ TESTRDIR
; Not read, check user directory
117 MOV WORD PTR [UCOMBUF
+1],0D01H ; Reset buffer
121 JZ NOSETBUF
; User directory OK
126 MOV DX,OFFSET TRANGROUP
:USERDIR1
128 INT int_command
; Restore users directory
133 JZ NOPCLOSE
; Don't bother if they don't exist
135 JNZ NOPCLOSE
; Don't del if still piping
138 MOV [EXTCOM
],0 ; Flag internal command
139 MOV [RESTDIR
],0 ; Flag users dirs OK
140 MOV AX,CS ; Get segment we're in
144 MOV DX,OFFSET TRANGROUP
:INTERNATVARS
145 MOV AX,INTERNATIONAL
SHL 8
148 SUB AX,[TPA
] ; AX=size of TPA in paragraphs
150 MUL DX ; DX:AX=size of TPA in bytes
151 OR DX,DX ; See if over 64K
152 JZ SAVSIZ
; OK if not
153 MOV AX,-1 ; If so, limit to 65535 bytes
155 MOV [BYTCNT
],AX ; Max no. of bytes that can be buffered
156 MOV DS,[RESSEG
] ; All batch work must use resident seg.
159 JZ GETCOM
; Don't do the CRLF
164 MOV AH,GET_DEFAULT_DRIVE
168 JZ NOPDRV
; No prompt if echo off
171 CALL PRINT_PROMPT
; Prompt the user
173 TEST [PIPEFLAG
],-1 ; Pipe has highest presedence
175 JMP PIPEPROC
; Continue the pipeline
177 TEST [FORFLAG
],-1 ; FOR has next highest precedence
179 JMP FORPROC
; Continue the FOR
181 MOV [RE_INSTR
],0 ; Turn redirection back off
184 TEST [BATCH
],-1 ; Batch has lowest precedence
186 JMP READBAT
; Continue BATCH
193 MOV DI,OFFSET TRANGROUP
:COMBUF
+ 2
210 POP DS ; Need local segment to point to buffer
211 MOV DX,OFFSET TRANGROUP
:UCOMBUF
212 MOV AH,STD_CON_STRING_INPUT
213 INT int_command
; Get a command
217 MOV SI,OFFSET TRANGROUP
:UCOMBUF
218 MOV DI,OFFSET TRANGROUP
:COMBUF
219 REP MOVSB ; Transfer it to the cooked buffer
222 ; All batch proccessing has DS set to segment of resident portion
223 ASSUME
DS:RESGROUP
,ES:TRANGROUP
230 MOV DI,OFFSET TRANGROUP
:ID
240 MOV BYTE PTR ES:[DI-1],"="
242 MOV SI,OFFSET TRANGROUP
:ID
244 POP DS ; DS:SI POINTS TO NAME
245 ASSUME
DS:TRANGROUP
,ES:RESGROUP
246 CALL FIND_NAME_IN_environment
251 ASSUME
DS:RESGROUP
,ES:TRANGROUP
253 POP DI ; get back pointer to command line
256 GETENV3: ; Parameter not found
259 MOV SI,OFFSET TRANGROUP
:ID
262 LODSB ; From resident segment
263 OR AL,AL ; Check for end of parameter
284 CMP AL,"%" ; Check for two consecutive %
286 CMP AL,13 ; Check for end-of-line
292 JB NEEDENV
; look for parameter in the environment
298 SHL SI,1 ; Two bytes per entry
311 CMP SI,-1 ; Check if parameter exists
312 JZ RDBAT
; Ignore if it doesn't
314 LODSB ; From resident segment
315 CMP AL,0DH ; Check for end of parameter
321 MOV DX,OFFSET TRANGROUP
:NEEDBAT
323 JZ AskForBat
; Media is removable
325 MOV ES,[BATCH
] ; Turn off batch
327 INT int_command
; free up the batch piece
328 MOV [BATCH
],0 ; AFTER DEALLOC in case of ^C
329 MOV [FORFLAG
],0 ; Turn off for processing
330 MOV [PIPEFLAG
],0 ; Turn off any pipe
333 MOV DX,OFFSET TRANGROUP
:BADBAT
334 CALL ERROR_PRINT
; Tell user no batch file
340 CALL ERROR_PRINT
; Prompt for batch file
343 ;**************************************************************************
344 ; read the next keystroke
347 MOV AX,(STD_CON_INPUT_FLUSH
SHL 8) OR STD_CON_INPUT_no_echo
348 INT int_command
; Get character with KB buffer flush
349 MOV AX,(STD_CON_INPUT_FLUSH
SHL 8) + 0
356 MOV DI,OFFSET TRANGROUP
:COMBUF
+2
359 CMP AL,':' ; Label/Comment?
361 NOPLINE: ; Consume the line
365 CALL GETBATBYT
; Eat Linefeed
368 JMP TCOMMAND
; Hit EOF
373 CMP AL,"%" ; Check for parameter
380 SUB DI,OFFSET TRANGROUP
:COMBUF
+3
382 MOV ES:[COMBUF
+1],AL ; Set length of line
383 CALL GETBATBYT
; Eat linefeed
387 POP DS ; Go back to local segment
390 MOV DX,OFFSET TRANGROUP
:COMBUF
+2
393 ; All segments are local for command line processing
398 CALL PRESCAN
; Cook the input buffer
400 JMP PIPEPROCSTRT
; Fire up the pipe
402 MOV SI,OFFSET TRANGROUP
:COMBUF
+2
403 MOV DI,OFFSET TRANGROUP
:IDLEN
404 MOV AX,(PARSE_FILE_DESCRIPTOR
SHL 8) OR 01H ; Make FCB with blank scan-off
406 CMP AL,1 ; Check for ambiguous command name
407 JZ BADCOMJ1
; Ambiguous commands not allowed
421 REPNE SCASB ; Count no. of letters in command name
430 STOSB ; Move command tail to 80H
434 MOV BYTE PTR DS:[80H
],CL
436 ; If the command has 0 parameters must check here for
437 ; any switches that might be present.
438 ; SI -> first character after the command.
439 CALL SWITCH
; Is the next character a SWITCHAR
442 MOV AX,(PARSE_FILE_DESCRIPTOR
SHL 8) OR 01H
444 MOV [PARM1
],AL ; Save result of parse
459 MOV AX,(PARSE_FILE_DESCRIPTOR
SHL 8) OR 01H
460 INT int_command
; Parse file name
461 MOV [PARM2
],AL ; Save result
466 SWTLP: ; Find any remaining switches
467 CMP BYTE PTR [SI],0DH
477 OR DL,DL ; Check if drive was specified
481 DEC AL ; Check for null command
494 XCHG AX,BX ; Put switches in AX
498 XOR BX,BX ; Initialize - no switches set
500 CALL SCANOFF
; Skip any delimiters
501 CMP AL,[SWITCHAR
] ; Is it a switch specifier?
502 JNZ RETSW
; No -- we're finished
503 OR BX,GOTSWITCH
; Indicate there is a switch specified
504 INC SI ; Skip over the switch character
509 ; Convert lower case input to upper case
511 MOV DI,OFFSET TRANGROUP
:SWLIST
513 REPNE SCASB ; Look for matching switch
516 SHL AX,CL ; Set a bit for the switch
527 MOV DX,OFFSET TRANGROUP
:BADDRV
531 MOV SI,OFFSET TRANGROUP
:COMTAB
; Prepare to search command table
534 MOV DI,OFFSET TRANGROUP
:IDLEN
539 ADD SI,CX ; Bump to next position without affecting flags
541 LODSB ; Get flag for drive check
543 LODSW ; Get address of command
549 OR AL,[PARM2
] ; Check if either parm. had invalid drive
554 CALL DX ; Call the internal
562 DEC DL ; Adjust for correct drive number
563 DEC AL ; Check if anything else is on line
569 CALL SAVUDIR
; Drive letter already checked
571 MOV DI,OFFSET TRANGROUP
:COM
572 STOSB ; Look for any extension
575 MOV DX,OFFSET TRANGROUP
:DIRBUF
; Command will end up here
583 MOV DI,OFFSET TRANGROUP
:EXECPATH
584 MOV BYTE PTR [DI],0 ; Initialize to current directory
586 MOV AH,DIR_SEARCH_FIRST
590 MOV DX,OFFSET TRANGROUP
:IDLEN
593 MOV AH,DIR_SEARCH_NEXT
; Do search-next next
595 CMP WORD PTR [DIRBUF
+9],4F00H
+ "C"
600 JMP EXECUTE
; If we find a COM were done
603 CMP WORD PTR [DIRBUF
+9],5800H
+ "E"
607 OR [FILTYP
],1 ; Flag an EXE found
608 JMP COMSRCH
; Continue search
611 CMP WORD PTR [DIRBUF
+9],4100H
+ "B"
615 OR [FILTYP
],2 ; Flag BAT found
616 JMP COMSRCH
; Continue search
621 MOV WORD PTR [DIRBUF
+9],5800H
+"E"
623 JMP EXECUTE
; Found EXE
627 JZ NEXTPATH
; Found nothing, try next path
628 MOV WORD PTR [DIRBUF
+9],4100H
+"B"
630 MOV DX,OFFSET TRANGROUP
:DIRBUF
; Found BAT
634 JZ BATCOMJ
; Bat exists
642 MOV DX,OFFSET TRANGROUP
:USERDIR1
; Restore users dir
649 MOV DI,OFFSET TRANGROUP
:EXECPATH
; Build a full path here
651 MOV DS,[ENVIRSEG
] ; Point into environment
660 JZ BADCOMJ
; NUL, command not found
661 XOR BL,BL ; Make BL a NUL
662 PSKIPLP: ; Get the path
668 CMP DI,15+DirStrLen
+(OFFSET TRANGROUP
:EXECPATH
)
671 LODSB ; scan to end of path element
695 MOV BYTE PTR ES:[DI-1],';' ; Fix up the NUL in EXECPATH
696 DEC SI ; Point to the NUL in PATHSTRING
697 MOV BL,[SI-1] ; Change substi char to char before NUL
700 DEC DI ; Point to the end of the dir
706 CMP BYTE PTR [SI+1],DRVCHAR
707 JNZ DEFDRVPATH
; No drive spec
715 MOV [IDLEN
],DL ; New drive
717 CALL SAVUDIR
; Save the users dir
720 MOV DX,OFFSET TRANGROUP
:BADPMES
; Tell the user bad stuff in path
728 XCHG BL,[SI-1] ; Stick in NUL, or same thing if LASTPATH
732 MOV [SI-1],BL ; Fix the path string back up
735 INC [RESTDIR
] ; Say users dir needs restoring
737 JMP BADPATHEL
; Ignore a directory which doesn't exist
739 JMP RESEARCH
; Try looking in this one
743 ; Batch parameters are read with ES set to segment of resident part
744 CALL IOSET
; Set up any redirection
747 ;Since BATCH has lower precedence than PIPE or FOR. If a new BATCH file
748 ;is being started it MUST be true that no FOR or PIPE is currently in
750 MOV [FORFLAG
],0 ; Turn off for processing
751 MOV [PIPEFLAG
],0 ; Turn off any pipe
753 JNZ CHAINBAT
; Don't need allocation if chaining
756 MOV BX,6 ; 64 + 32 bytes
758 INT int_command
; Suck up a little piece for batch processing
767 CALL SAVUDIR1
; ES:DI set up, get dir containing Batch file
771 REPNZ SCASB ; Find the NUL
772 DEC DI ; Point at the NUL
778 MOV SI,OFFSET TRANGROUP
:DIRBUF
+1
779 CALL FCB_TO_ASCZ
; Tack on batch file name
783 REP STOSW ; Init Parmtab to no parms
787 MOV SI,OFFSET TRANGROUP
:COMBUF
+2
788 MOV DI,OFFSET RESGROUP
:PARMBUF
794 JCXZ MOVPARM
; Only first 10 parms get pointers
797 MOV ES:[BX],DI ; Set pointer table to point to actual parameter
804 JZ ENDPARM
; Check for end of parameter
811 STOSB ; End-of-parameter marker
817 STOSB ; Nul terminate the parms
820 POP DS ; Simply batch FCB setup
822 MOV WORD PTR [BATLOC
],AX ; Start at beginning of file
823 MOV WORD PTR [BATLOC
+2],AX
826 MOV [SINGLECOM
],0FFF0H ; Flag single command BATCH job
829 ASSUME
DS:TRANGROUP
,ES:TRANGROUP
834 CMP BYTE PTR [DI],0 ; Command in current directory
840 JNZ StuffPath
; Last char is second KANJI byte, might be '\'
844 JZ HAVEXP
; Don't double slash
851 MOV AL,[DIRBUF
] ; Specify a drive
857 MOV SI,OFFSET TRANGROUP
:DIRBUF
+1
858 CALL FCB_TO_ASCZ
; Tack on the filename
862 INT int_command
; Now running in "free" space
865 INC [EXTCOM
] ; Indicate external command
866 MOV [RESTDIR
],0 ; Since USERDIR1 is in transient, insure
867 ; this flag value for re-entry to COMMAND
871 REP MOVSW ; Transfer parameters to resident header
872 MOV DX,OFFSET TRANGROUP
:EXECPATH
873 MOV BX,OFFSET RESGROUP
:EXEC_BLOCK
875 JMP [EXEC_ADDR
] ; Jmp to the EXEC in the resident
880 MOV DX,OFFSET TRANGROUP
:BADNAM
889 CMP [SINGLECOM
],0EFFFH
910 MOV DX,OFFSET TRANGROUP
:NOTFND
914 ; Make sure last line ends with CR/LF
916 CMP AL,[LINCNT
] ; Will be equal if just had CR/LF
920 MOV DX,OFFSET TRANGROUP
:DIRMES_PRE
925 MOV DX,OFFSET TRANGROUP
:DIRMES_POST
927 MOV AH,GET_DRIVE_FREESPACE
928 MOV DL,BYTE PTR DS:[FCB
]
932 MOV DX,OFFSET TRANGROUP
:BYTMES_PRE
934 MUL CX ; AX is bytes per cluster
939 MOV DX,OFFSET TRANGROUP
:BYTMES_POST
946 MOV DX,OFFSET RESGROUP
:PIPE1
; Clean up in case ^C
949 MOV DX,OFFSET RESGROUP
:PIPE2
953 MOV WORD PTR [PIPEFLAG
],AX ; Pipe files and pipe gone
954 MOV [ECHOFLAG
],1 ; Make sure ^C to pipe doesn't leave ECHO OFF
959 MOV DX,OFFSET TRANGROUP
:SYNTMES
962 MOV DX,OFFSET TRANGROUP
:PIPEEMES
970 ASSUME
DS:TRANGROUP
,ES:TRANGROUP
973 INC [PIPEFILES
] ; Flag that the pipe files exist
974 MOV AH,19H
; Get current drive
977 MOV [PIPE2
],AL ; Make pipe files in root of def drv
978 MOV BX,OFFSET RESGROUP
:PIPE1
984 JC PIPEERR
; Couldn't create
986 MOV AH,CLOSE
; Don't proliferate handles
988 MOV DX,OFFSET RESGROUP
:PIPE2
995 CALL TESTDOREIN
; Set up a redirection if specified
996 MOV [ECHOFLAG
],0 ; No echo on pipes
1000 MOV [SINGLECOM
],0F000H ; Flag single command pipe
1006 MOV [ECHOFLAG
],0 ; No echo on pipes
1010 JNZ PIPEEND
; Pipe done
1011 MOV DX,[INPIPEPTR
] ; Get the input file name
1015 JC PIPEERR
; Lost the pipe file
1018 XCHG AL,[BX.PDB_JFN_Table
]
1019 MOV DS:[PDB_JFN_Table
],AL ; Redirect
1021 MOV DI,OFFSET TRANGROUP
:COMBUF
+ 2
1023 CMP BYTE PTR [SI],0DH ; '|<CR>'
1028 CMP BYTE PTR [SI],'|' ; '||'
1048 MOV BYTE PTR ES:[DI-1],0DH
1052 MOV [PIPEPTR
],SI ; On to next pipe element
1056 MOV AX,(CREAT
SHL 8)
1059 JC PIPEERRJ
; Lost the file
1062 XCHG AL,[BX.PDB_JFN_Table
]
1063 MOV DS:[PDB_JFN_Table
+1],AL
1064 XCHG DX,[INPIPEPTR
] ; Swap for next element of pipe
1071 MOV [PIPEPTR
],SI ; Point at the CR (anything not '|' will do)
1072 CALL TESTDOREOUT
; Set up the redirection if specified
1076 JMP NOPIPEPROC
; Process the pipe element
1080 CMP [SINGLECOM
],0F000H
1082 MOV [SINGLECOM
],-1 ; Make it return