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 ; '|' 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