page 80,132 ; SCCSID = @(#)tmisc1.asm 4.1 85/09/22 ; SCCSID = @(#)tmisc1.asm 4.1 85/09/22 TITLE Part7 COMMAND Transient Routines ; More misc routines .xlist .xcref INCLUDE comsw.asm INCLUDE DOSSYM.INC INCLUDE comseg.asm INCLUDE comequ.asm .list .cref CODERES SEGMENT PUBLIC BYTE ;AC000; EXTRN RSTACK:BYTE CodeRes ENDS DATARES SEGMENT PUBLIC BYTE ;AC000; EXTRN CALL_FLAG:BYTE EXTRN EchoFlag:BYTE EXTRN EXEC_BLOCK:BYTE EXTRN EXTCOM:BYTE EXTRN PIPEFLAG:BYTE EXTRN PIPEPTR:WORD EXTRN PIPESTR:BYTE EXTRN RESTDIR:BYTE EXTRN RE_OUT_APP:BYTE EXTRN RE_OUTSTR:BYTE DATARES ENDS TRANDATA SEGMENT PUBLIC BYTE ;AC000; EXTRN BADDRV_PTR:WORD EXTRN BADNAM_PTR:WORD EXTRN COMTAB:BYTE ;AC000; EXTRN extend_buf_ptr:word ;AN000; EXTRN msg_disp_class:byte ;AN000; TRANDATA ENDS TRANSPACE SEGMENT PUBLIC BYTE ;AC000; EXTRN arg:byte ; the arg structure! EXTRN APPEND_EXEC:BYTE ;AN041; EXTRN CHKDRV:BYTE EXTRN COMBUF:BYTE EXTRN EXECPATH:BYTE EXTRN EXEC_ADDR:DWORD EXTRN FILTYP:BYTE EXTRN IDLEN:BYTE EXTRN KPARSE:BYTE ;AC000; EXTRN PARM1:BYTE EXTRN PARM2:BYTE EXTRN PathPos:word EXTRN RESSEG:WORD EXTRN RE_INSTR:BYTE EXTRN SPECDRV:BYTE EXTRN SWITCHAR:BYTE EXTRN switch_list:byte EXTRN TRAN_TPA:WORD IF IBM EXTRN ROM_CALL:BYTE EXTRN ROM_CS:WORD EXTRN ROM_IP:WORD ENDIF TRANSPACE ENDS TRANCODE SEGMENT PUBLIC byte ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING EXTRN APPEND_PARSE:NEAR ;AN010; EXTRN BATCOM:NEAR EXTRN DOCOM1:NEAR EXTRN PIPEERRSYN:NEAR EXTRN TCOMMAND:NEAR IF IBM EXTRN ROM_EXEC:NEAR EXTRN ROM_SCAN:NEAR ENDIF PUBLIC CERROR PUBLIC DRVBAD PUBLIC EXTERNAL PUBLIC FNDCOM PUBLIC PRESCAN PUBLIC SWITCH ASSUME DS:TRANGROUP ;--------------------------- ; We can get rid of this switch processing code if we can take ; care of the remaining two calls to switch, later in the file. ; However, I have not checked whether or not any other files use ; switch -- after all, it IS public! ;--------------------------- RETSW: XCHG AX,BX ; Put switches in AX return SWITCH: XOR BX,BX ; Initialize - no switches set SWLOOP: INVOKE SCANOFF ; Skip any delimiters CMP AL,[SWITCHAR] ; Is it a switch specifier? JNZ RETSW ; No -- we're finished OR BX,fSwitch ; Indicate there is a switch specified INC SI ; Skip over the switch character INVOKE SCANOFF CMP AL,0DH JZ RETSW ; Oops INC SI ; Convert lower case input to upper case INVOKE UPCONV MOV DI,OFFSET TRANGROUP:switch_list 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 SWCOUNT EQU 5 ; Length of switch_list DRVBAD: MOV DX,OFFSET TRANGROUP:BADDRV_ptr JMP CERROR externalj: jmp EXTERNAL fndcom: ; search the internal command table OR AL,AL ; Get real length of first arg jz externalj ; If 0, it must begin with "\" so has ; to be external. ; barryf code starts here IF IBM call test_append ; see if APPEND installed je contcom ; not loaded append_internal: mov cl,TRANGROUP:IDLEN mov ch,0 mov pathpos,cx inc append_exec ;AN041; set APPEND to ON invoke ioset ; re-direct the o'l io mov SI, offset TRANGROUP:IDLEN ; address command name, DS already set mov DX,-1 ; set invoke function mov di,offset TRANGROUP:APPEND_PARSE;AN010; Get the entry point for PARSE for APPEND mov AX,0AE01H int 2FH ; execute command cmp TRANGROUP:IDLEN,0 ; execute requested jne contcom jmp Cmd_done contcom: ; continue with internal scan ENDIF ; barryf code ends here mov DI, OFFSET TRANGROUP:COMTAB XOR CX,CX findcom: mov SI, offset TRANGROUP:IDLEN+1 ; pointer to command argument mov CL, [DI] ; load length of internal command inc di ; advance past length jcxz externalj ; if it's zero, we're out of internals cmp CL, IDLEN ; that of the command argument jnz abcd ; lengths not equal ==> strings not eq MOV PathPos,CX ; store length of command repz cmpsb abcd: lahf ; save the good ol' flags add DI, CX ; skip over remaining internal, if any mov AL, BYTE PTR [DI] ; load drive-check indicator byte (DCIB) mov [CHKDRV], AL ; save command flag byte in chkdrv inc DI ; increment DI (OK, OK, I'll stop) mov BX, WORD PTR [DI] ; load internal command address inc DI ; skip over the puppy inc DI sahf ; remember those flags? jnz findcom ; well, if all the cmps worked... ; ; All messages get redirected. ; cmp append_exec,0 ;AN041; APPEND just executed? jnz dont_set_io ;AN041; Yes - this junk is already set invoke ioset ; re-direct the ol' i/o dont_set_io: ;AN041; invoke SETSTDINON ;AN026; turn on critical error on STDIN invoke SETSTDOUTOFF ;AN026; turn off critical error on STDOUT test [CHKDRV], fCheckDrive ; did we wanna check those drives? jz nocheck mov AL, [PARM1] ; parse_file_descriptor results tell or AL, [PARM2] ; us whether those drives were OK cmp AL, -1 jnz nocheck jmp drvbad ; ; The user may have omitted the space between the command and its arguments. ; We need to copy the remainder of the user's command line into the buffer. ; Note that thisdoes not screw up the arg structure; it points into COMBUF not ; into the command line at 80. ; nocheck: call cmd_copy switcheck: test [CHKDRV], fSwitchAllowed ; Does the command take switches jnz realwork ; Yes, process the command call noswit ; No, check to see if any switches jnz realwork ; None, process the command mov msg_disp_class,parse_msg_class ;AN000; set up parse error msg class MOV DX,OFFSET TranGroup:Extend_Buf_ptr ;AC000; get extended message pointer mov Extend_Buf_ptr,BadSwt_ptr ;AN000; get "Invalid switch" message number jmp CERROR ; Print error and chill out... realwork: call BX ; do some real work, at last ; See if we're in a batch CALL command. If we are, reprocess the command line, ; otherwise, go get another command. Cmd_done: push cs ; g restore data segment pop ds ; g push ds ; g save data segment mov ds,[resseg] ; g get segment containing call flag ASSUME ds:resgroup cmp call_flag, call_in_progress ; G Is a call in progress? mov call_flag, 0 ; G Either way, reset flag pop ds ; g get data segment back jz incall ; G jmp tcommand ; chill out... incall: JMP DOCOM1 noswit: push di ; Save di mov di,81h ; di = ptr to command args mov si,80h ; Get address of length of command args lodsb ; Load length mov cl,al ; Move length to cl xor ch,ch ; Zero ch mov al,[SWITCHAR] ; al = switch character cmp al,0 ; Turn off ZF repnz scasb ; Scan for a switch character and return pop di ; with ZF set if one was found ret EXTERNAL: IF IBM call test_append ; check to see if append installed je not_barryf ; no - truly external command jmp append_internal ; yes - go to Barryf code not_barryf: ENDIF MOV [FILTYP],0 MOV DL,[SPECDRV] MOV [IDLEN],DL IF IBM MOV [ROM_CALL],0 PUSH DX MOV DX,OFFSET TRANGROUP:IDLEN CALL ROM_SCAN POP DX JNC DO_SCAN INC [ROM_CALL] JMP PostSave DO_SCAN: ENDIF IF IBM PostSave: ENDIF MOV DI,OFFSET TRANGROUP:EXECPATH MOV BYTE PTR [DI],0 ; Initialize to current directory IF IBM CMP [ROM_CALL],0 JZ Research JMP NeoExecute ENDIF RESEARCH: invoke path_search ; find the mother (result in execpath) or AX, AX ; did we find anything? je badcomj45 ; null means no (sob) cmp AX, 04H ; 04H and 08H are .exe and .com jl rsrch_br1 ; fuckin' sixteen-bit machine ought jmp execute ; to be able to handle a SIXTEEN-BIT rsrch_br1: ; DISPLACEMENT!! jmp batcom ; 02H is .bat BADCOMJ45: JMP BADCOM ASSUME DS:TRANGROUP,ES:TRANGROUP EXECUTE: NeoExecute: invoke IOSET invoke SETSTDINOFF ;AN026; turn off critical error on STDIN invoke SETSTDOUTOFF ;AN026; turn off critical error on STDOUT MOV ES,[TRAN_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 ; moving (100h-5Ch)/2 = 80h-2Eh REP MOVSW ; Transfer parameters to resident header MOV DX,OFFSET TRANGROUP:EXECPATH MOV BX,OFFSET RESGROUP:EXEC_BLOCK MOV AX,EXEC SHL 8 IF IBM TEST [ROM_CALL],-1 JZ OK_EXEC JMP ROM_EXEC OK_EXEC: ENDIF ; ; we are now running in free space. anything we do from here on may get ; trashed. Move the stack (also in free space) to allocated space because ; since EXEC restores the stack, somebody may trash what is on the stack. ; MOV CX,ES MOV SS,CX MOV SP,OFFSET RESGROUP:RSTACK JMP [EXEC_ADDR] ; Jmp to the EXEC in the resident BADCOM: PUSH CS POP DS MOV DX,OFFSET TRANGROUP:BADNAM_ptr CERROR: INVOKE std_eprintf JMP TCOMMAND ; ; Prescan converts the input buffer into a canonicalized form. All ; redirections and pipes are removed. ; PRESCAN: ; Cook the input buffer ASSUME DS:TRANGROUP,ES:TRANGROUP XOR CX,CX MOV ES,[RESSEG] ASSUME ES:RESGROUP MOV SI,OFFSET TRANGROUP:COMBUF+2 MOV DI,SI CountQuotes: LODSB ; get a byte CMP AL,22h ; is it a quote? JNZ CountEnd ; no, try for end of road INC CH ; bump count JMP CountQuotes ; go get next char CountEnd: CMP AL,13 ; end of road? JNZ CountQuotes ; no, go back for next char ;;;; IF KANJI 3/3/KK PUSH CX ; save count MOV SI,DI ; get back beginning of buffer KanjiScan: LODSB ; get a byte INVOKE TestKanj ; is it a leadin byte JZ KanjiQuote ; no, check for quotes MOV AH,AL ; save leadin LODSB ; get trailing byte CMP AX,8140h ; is it Kanji space JNZ KanjiScan ; no, go get next MOV [SI-2],2020h ; replace with spaces JMP KanjiScan ; go get next char KanjiQuote: CMP AL,22h ; beginning of quoted string JNZ KanjiEnd ; no, check for end DEC CH ; drop count JZ KanjiScan ; if count is zero, no quoting KanjiQuoteLoop: LODSB ; get next byte CMP AL,22h ; is it another quote JNZ KanjiQuoteLoop ; no, get another DEC CH ; yes, drop count JMP KanjiScan ; go get next char KanjiEnd: CMP AL,13 ; end of line character? JNZ KanjiScan ; go back to beginning POP CX ; get back original count ;;;; ENDIF 3/3/KK MOV SI,DI ; restore pointer to begining PRESCANLP: LODSB ;;;; IF KANJI 3/3/KK INVOKE TESTKANJ JZ NOTKANJ6 MOV [DI],AL INC DI ; fake STOSB into DS LODSB ; grab second byte MOV [DI],AL ; fake stosb into DS INC DI INC CL INC CL JMP PRESCANLP NOTKANJ6: ;;;; ENDIF 3/3/KK CMP AL,'"' ; " character JNZ TRYGREATER DEC CH JZ TRYGREATER QLOOP: MOV [DI],AL INC DI INC CL LODSB CMP AL,'"' ; " character JNZ QLOOP DEC CH TRYGREATER: CMP AL,rabracket JNZ NOOUT ; ; We have found a ">" char. We need to see if there is another ">" ; following it. ; CMP BYTE PTR [SI],al JNZ NOAPPND LODSB INC [RE_OUT_APP] ; Flag >> NOAPPND: ; ; Now we attempt to find the file name. First, scan off all whitespace ; INVOKE SCANOFF CMP AL,labracket ;AN040; was there no filename? JZ REOUT_ERRSET ;AN040; yes - set up error CMP AL,0DH JNZ GOTREOFIL ; ; There was no file present. Set us up at end-of-line. ; REOUT_ERRSET: ;AN040; set up for an error mov byte ptr [di], 0dh ; Clobber first ">" MOV WORD PTR [RE_OUTSTR],09H ; Cause an error later JMP PRESCANEND GOTREOFIL: PUSH DI MOV DI,OFFSET RESGROUP:RE_OUTSTR MOV BX,DI PUSH ES SETREOUTSTR: ; Get the output redirection name LODSB CMP AL,0DH JZ GOTRESTR INVOKE DELIM JZ GOTRESTR CMP AL,[SWITCHAR] JZ GOTRESTR CMP AL,'"' ;AN033; Is the character a quote? JZ PIPEERRSYNJ5 ;AN033; Yes - get out quick - or system crashes CMP AL,labracket ;AN002; Is char for input redirection JZ ABRACKET_TERM ;AN002; yes - end of string CMP AL,rabracket ;AN002; Is char for output redirection JNZ NO_ABRACKET ;AN002; no - not end of string abracket_term: ;AN002; have end of string by < or > DEC SI ;AN002; back up over symbol MOV AL,BLANK ;AN002; show delimiter as char JMP SHORT GOTRESTR ;AN002; go process it no_abracket: ;AN002; not at end of string STOSB ; store it into resgroup JMP SHORT SETREOUTSTR NOOUT: CMP AL,labracket JNZ CHKPIPE mov bx,si ; Save loc of "<" INVOKE SCANOFF CMP AL,rabracket ;AN040; was there no filename? JZ REIN_ERRSET ;AN040; yes - set up error CMP AL,0DH JNZ GOTREIFIL REIN_ERRSET: ;AN040; set up for error mov byte ptr [di],0dh ; Clobber "<" MOV WORD PTR [RE_INSTR],09H ; Cause an error later JMP SHORT PRESCANEND GOTREIFIL: PUSH DI MOV DI,OFFSET TranGROUP:RE_INSTR MOV BX,DI PUSH ES PUSH CS POP ES ; store in TRANGROUP JMP SHORT SETREOUTSTR ; Get the input redirection name CHKPIPE: MOV AH,AL CMP AH,AltPipeChr JZ IsPipe3 CMP AH,vbar JNZ CONTPRESCAN IsPipe3: ; ; Only push the echo flag if we are entering the pipe for the first time. ; CMP PipeFlag,0 JNZ NoEchoPush SHL EchoFlag,1 ; push echo state and turn it off NoEchoPush: INC [PIPEFLAG] INVOKE SCANOFF CMP AL,0DH JZ PIPEERRSYNJ5 CMP AL,AltPipeChr JZ PIPEERRSYNJ5 CMP AL,vbar ; Double '|'? JNZ CONTPRESCAN PIPEERRSYNJ5: PUSH ES POP DS ; DS->RESGROUP JMP PIPEERRSYN ; ; Trailing :s are allowed on devices. Check to be sure that there is more ; than just a : in the redir string. ; GOTRESTR: XCHG AH,AL mov al,':' SUB BX,DI ; compute negatinve of number of chars CMP BX,-1 ; is there just a :? JZ NotTrailCol ; yep, don't change CMP BYTE PTR ES:[DI-1],al ; Trailing ':' OK on devices JNZ NOTTRAILCOL DEC DI ; Back up over trailing ':' NOTTRAILCOL: XOR AL,AL STOSB ; NUL terminate the string POP ES POP DI ; Remember the start CONTPRESCAN: MOV [DI],AH ; "delete" the redirection string INC DI CMP AH,0DH JZ PRESCANEND INC CL JMP PRESCANLP PRESCANEND: CMP [PIPEFLAG],0 JZ ISNOPIPE MOV DI,OFFSET RESGROUP:PIPESTR MOV [PIPEPTR],DI MOV SI,OFFSET TRANGROUP:COMBUF+2 INVOKE SCANOFF PIPESETLP: ; Transfer the pipe into the resident LODSB ; pipe buffer STOSB CMP AL,0DH JNZ PIPESETLP ISNOPIPE: MOV [COMBUF+1],CL CMP [PIPEFLAG],0 PUSH CS POP ES return cmd_copy proc near MOV SI,OFFSET TRANGROUP:COMBUF+2 INVOKE Scanoff ; advance past separators... add si,PathPos mov di,81h xor cx,cx CmdCopy: lodsb stosb cmp al,0dh jz CopyDone inc cx jmp CmdCopy CopyDone: mov byte ptr ds:[80h],cl ; Store count ret cmd_copy endp test_append proc near mov BX,offset TRANGROUP:COMBUF ; barry can address mov SI, offset TRANGROUP:IDLEN ; address command name, DS already set mov DX,-1 ; set install check function mov AX,0AE00H int 2FH ; see if loaded cmp AL,00H ret test_append endp TRANCODE ENDS END