You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1825 lines
55 KiB
1825 lines
55 KiB
page ,132
|
|
; SCCSID = @(#)tcode.asm 1.1 85/05/14
|
|
; SCCSID = @(#)tcode.asm 1.1 85/05/14
|
|
TITLE Part1 COMMAND Transient Routines
|
|
;/*
|
|
; * Microsoft Confidential
|
|
; * Copyright (C) Microsoft Corporation 1991
|
|
; * All Rights Reserved.
|
|
; */
|
|
|
|
;
|
|
; Revision History
|
|
; ================
|
|
;
|
|
; M025 SR 9/12/90 Removed calls to SetStdInOn,SetStdInOff
|
|
; SetStdOutOn & SetStdOutOff.
|
|
;
|
|
|
|
|
|
.xlist
|
|
.xcref
|
|
include comsw.asm
|
|
include dossym.inc
|
|
include syscall.inc
|
|
include comseg.asm
|
|
include comequ.asm
|
|
include cmdsvc.inc
|
|
include mult.inc
|
|
ifdef NEC_98
|
|
include pdb.inc
|
|
endif ;NEC_98
|
|
include vint.inc
|
|
.list
|
|
.cref
|
|
|
|
Prompt32 equ 1
|
|
Start16 equ 0
|
|
Return16 equ 1
|
|
DOSONLY_YES equ 1
|
|
FOR_TSR equ 0
|
|
FOR_SHELLOUT equ 1
|
|
|
|
|
|
CODERES SEGMENT PUBLIC BYTE ;AC000;
|
|
EXTRN EXEC_WAIT:NEAR
|
|
CODERES ENDS
|
|
|
|
DATARES SEGMENT PUBLIC BYTE ;AC000;
|
|
EXTRN BATCH:WORD
|
|
EXTRN CALL_BATCH_FLAG:byte
|
|
EXTRN CALL_FLAG:BYTE
|
|
EXTRN ECHOFLAG:BYTE
|
|
EXTRN envirseg:word
|
|
EXTRN EXTCOM:BYTE
|
|
EXTRN FORFLAG:BYTE
|
|
EXTRN IFFLAG:BYTE
|
|
EXTRN next_batch:word
|
|
EXTRN nullflag:byte
|
|
EXTRN PIPEFILES:BYTE
|
|
EXTRN PIPEFLAG:BYTE
|
|
EXTRN RE_OUT_APP:BYTE
|
|
EXTRN RE_OUTSTR:BYTE
|
|
EXTRN RESTDIR:BYTE
|
|
EXTRN SINGLECOM:WORD
|
|
EXTRN KSWITCHFLAG:BYTE
|
|
EXTRN VERVAL:WORD
|
|
EXTRN SCS_Is_First:BYTE
|
|
EXTRN SCS_PAUSE:BYTE
|
|
EXTRN SCS_REENTERED:BYTE
|
|
EXTRN SCS_FIRSTCOM:BYTE
|
|
EXTRN SCS_CMDPROMPT:BYTE
|
|
EXTRN SCS_DOSONLY:BYTE
|
|
EXTRN SCS_PROMPT16:BYTE
|
|
EXTRN SCS_FIRSTTSR:BYTE
|
|
EXTRN RES_RDRINFO:DWORD
|
|
EXTRN RES_BATSTATUS:BYTE
|
|
EXTRN crit_msg_off:word ;AC000;
|
|
EXTRN crit_msg_seg:word ;AC000;
|
|
EXTRN OldTerm:DWORD
|
|
EXTRN PARENT:WORD
|
|
extrn RetCode:word
|
|
extrn Io_Save:word
|
|
extrn Io_Stderr:byte
|
|
extrn RES_TPA:WORD ; YST
|
|
extrn LTPA:WORD ; YST
|
|
DATARES ENDS
|
|
|
|
TRANDATA SEGMENT PUBLIC BYTE ;AC000;
|
|
EXTRN BadNam_Ptr:word ;AC000;
|
|
EXTRN comspec:byte
|
|
EXTRN NT_INTRNL_CMND:byte
|
|
TRANDATA ENDS
|
|
|
|
TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
|
|
EXTRN APPEND_EXEC:BYTE ;AN041;
|
|
EXTRN ARG1S:WORD
|
|
EXTRN ARG2S:WORD
|
|
EXTRN ARGTS:WORD
|
|
EXTRN BYTCNT:WORD
|
|
EXTRN COMBUF:BYTE
|
|
EXTRN COMSW:WORD
|
|
EXTRN CURDRV:BYTE
|
|
EXTRN HEADCALL:DWORD
|
|
EXTRN IDLEN:BYTE
|
|
EXTRN INTERNATVARS:BYTE
|
|
EXTRN PARM1:BYTE
|
|
EXTRN PARM2:BYTE
|
|
EXTRN RE_INSTR:BYTE
|
|
EXTRN RESSEG:WORD
|
|
EXTRN SPECDRV:BYTE
|
|
EXTRN STACK:WORD
|
|
EXTRN SWITCHAR:BYTE
|
|
EXTRN TPA:WORD
|
|
EXTRN UCOMBUF:BYTE
|
|
EXTRN USERDIR1:BYTE
|
|
IF IBM
|
|
EXTRN ROM_CALL:BYTE
|
|
EXTRN ROM_CS:WORD
|
|
EXTRN ROM_IP:WORD
|
|
ENDIF
|
|
EXTRN ENV_PTR_SEG:WORD
|
|
EXTRN ENV_SIZE:WORD
|
|
EXTRN SCS_TSREXIT:WORD
|
|
EXTRN CMD_PTR_SEG:WORD
|
|
EXTRN CMD_PTR_OFF:WORD
|
|
EXTRN CMD_SIZE:WORD
|
|
EXTRN SCS_EXIT_CODE:WORD
|
|
EXTRN SCS_RDRINFO:DWORD
|
|
EXTRN SCS_BATSTATUS:DWORD
|
|
EXTRN SCS_NUM_DRIVES:WORD
|
|
EXTRN SCS_CUR_DRIVE:WORD
|
|
EXTRN SCS_CODEPAGE:WORD
|
|
EXTRN SCS_STD_HANDLE:WORD
|
|
EXTRN SCS_STD_BITS:BYTE
|
|
EXTRN EXECPATH_SEG:WORD
|
|
EXTRN EXECPATH_OFF:WORD
|
|
EXTRN EXECPATH_SIZE:WORD
|
|
EXTRN EXECPATH:BYTE
|
|
|
|
EXTRN TRAN_TPA:WORD
|
|
extrn transpaceend:byte ; (YST)
|
|
|
|
TRANSPACE ENDS
|
|
|
|
; (YST)
|
|
TAIL segment public para
|
|
extrn TranStart:word
|
|
TAIL ENDS
|
|
; End of (YST)
|
|
|
|
|
|
; ********************************************************************
|
|
; 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 BYTE ;AC000;
|
|
|
|
ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
|
|
|
|
EXTRN $EXIT:NEAR
|
|
EXTRN DRVBAD:NEAR
|
|
EXTRN EXTERNAL:NEAR
|
|
EXTRN FNDCOM:NEAR
|
|
EXTRN FORPROC:NEAR
|
|
EXTRN PIPEPROC:NEAR
|
|
EXTRN PIPEPROCSTRT:NEAR
|
|
EXTRN GETENVSIZ:near
|
|
|
|
PUBLIC COMMAND
|
|
PUBLIC DOCOM
|
|
PUBLIC DOCOM1
|
|
PUBLIC NOPIPEPROC
|
|
PUBLIC TCOMMAND
|
|
|
|
IF IBM
|
|
PUBLIC ROM_EXEC
|
|
PUBLIC ROM_SCAN
|
|
ENDIF
|
|
|
|
|
|
; NTVDM use diff al value so we don't confuse dos 5.0
|
|
; NTVDM command.com GET_COMMAND_STATE equ 5500h
|
|
GET_COMMAND_STATE equ 5501h
|
|
|
|
NLSFUNC_installed equ 0ffh
|
|
KEYB16_installed equ 0ffh ; (YST)
|
|
CHECK_KEYB16 equ 0AD80h ; (YST)
|
|
set_global_cp equ 2
|
|
get_global_cp equ 1
|
|
|
|
|
|
ORG 0
|
|
ZERO = $
|
|
|
|
ORG 100H ; Allow for 100H parameter area
|
|
|
|
SETDRV:
|
|
MOV AH,SET_DEFAULT_DRIVE
|
|
INT 21h
|
|
;
|
|
; TCOMMAND is the recycle point in COMMAND. Nothing is known here.
|
|
; No registers (CS:IP) no flags, nothing.
|
|
;
|
|
|
|
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 21h
|
|
|
|
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
|
|
;
|
|
; Main entry point from resident portion.
|
|
;
|
|
; If BP <> 0, then we have just loaded transient portion otherwise we are
|
|
; just beginning the processing of another command.
|
|
;
|
|
|
|
COMMAND:
|
|
|
|
;
|
|
; We are not always sure of the state of the world at this time. We presume
|
|
; worst case and initialize the relevant registers: segments and stack.
|
|
;
|
|
ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
|
|
CLD
|
|
MOV AX,CS
|
|
FCLI
|
|
MOV SS,AX
|
|
ASSUME SS:TRANGROUP
|
|
MOV SP,OFFSET TRANGROUP:STACK
|
|
FSTI
|
|
MOV ES,AX
|
|
MOV DS,AX ;AN000; set DS to transient
|
|
ASSUME ES:TRANGROUP,DS:TRANGROUP ;AC000;
|
|
invoke TSYSLOADMSG ;AN000; preload messages
|
|
mov append_exec,0 ;AN041; set internal append state off
|
|
|
|
MOV DS,[RESSEG]
|
|
ASSUME DS:RESGROUP
|
|
|
|
MOV [UCOMBUF],COMBUFLEN ; Init UCOMBUF
|
|
MOV [COMBUF],COMBUFLEN ; Init COMBUF (Autoexec doing DATE)
|
|
|
|
mov [EXECPATH_SIZE], 0 ; ntvdm execpath extended
|
|
|
|
;
|
|
; If we have just loaded the transient, then we do NOT need to initialize the
|
|
; command buffer. ???? DO WE NEED TO RESTORE THE USERS DIRECTORY ???? I
|
|
; guess not: the only circumstances in which we reload the command processor
|
|
; is after a transient program execution. In this case, we let the current
|
|
; directory lie where it may.
|
|
;
|
|
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
|
|
;
|
|
; We have an unusual situation to handle. The user *may* have changed his
|
|
; directory as a result of an internal command that got aborted. Restoring it
|
|
; twice may not help us: the problem may never go away. We just attempt it
|
|
; once and give up.
|
|
;
|
|
MOV [RESTDIR],0 ; Flag users dirs OK
|
|
PUSH CS
|
|
POP DS
|
|
ASSUME DS:TRANGROUP
|
|
MOV DX,OFFSET TRANGROUP:USERDIR1
|
|
MOV AH,CHDIR
|
|
INT 21h ; 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
|
|
INVOKE PIPEDEL
|
|
|
|
NOPCLOSE:
|
|
MOV [EXTCOM],0 ; Flag internal command
|
|
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
|
|
PUSH BX
|
|
MOV BX,16
|
|
MUL BX ; DX:AX=size of TPA in bytes
|
|
POP BX
|
|
OR DX,DX ; See if over 64K
|
|
JZ SAVSIZ ; OK if not
|
|
MOV AX,-1 ; If so, limit to 65535 bytes
|
|
|
|
SAVSIZ:
|
|
;
|
|
; AX is the number of bytes free in the buffer between the resident and the
|
|
; transient with a maximum of 64K-1. We round this down to a multiple of 512.
|
|
;
|
|
CMP AX,512
|
|
JBE GotSize
|
|
AND AX,0FE00h ; NOT 511 = NOT 1FF
|
|
|
|
GotSize:
|
|
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
|
|
INVOKE SINGLETEST
|
|
JB GETCOM
|
|
TEST [PIPEFLAG],-1
|
|
JNZ GETCOM
|
|
TEST [FORFLAG],-1 ; G Don't print prompt in FOR
|
|
JNZ GETCOM ; G
|
|
TEST [BATCH], -1 ; G Don't print prompt if in batch
|
|
JNZ GETCOM ; G
|
|
; INVOKE CRLF2
|
|
|
|
GETCOM:
|
|
MOV CALL_FLAG,0 ; G Reset call flags
|
|
MOV CALL_BATCH_FLAG,0 ; G
|
|
MOV AH,GET_DEFAULT_DRIVE
|
|
INT 21h
|
|
MOV [CURDRV],AL
|
|
TEST [PIPEFLAG],-1 ; Pipe has highest presedence
|
|
JZ NOPIPE
|
|
JMP PIPEPROC ; Continue the pipeline
|
|
|
|
NOPIPE:
|
|
TEST [ECHOFLAG],1
|
|
JZ NOPDRV ; No prompt if echo off
|
|
INVOKE SINGLETEST
|
|
JB NOPDRV
|
|
TEST [FORFLAG],-1 ; G Don't print prompt in FOR
|
|
JNZ NOPDRV ; G
|
|
TEST [BATCH], -1 ; G Don't print prompt if in batch
|
|
JNZ TESTFORBAT ; G
|
|
; INVOKE PRINT_PROMPT ; Prompt the user
|
|
|
|
NOPDRV:
|
|
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
|
|
MOV IFFlag,0 ; no more ifs...
|
|
TEST [BATCH],-1 ; Batch has lowest precedence
|
|
JZ ISNOBAT
|
|
|
|
; Bugbug: MULT_SHELL_GET no longer used?
|
|
push es ;AN000; save ES
|
|
push ds ;AN000; save DS
|
|
mov ax,mult_shell_get ;AN000; check to see if SHELL has command
|
|
mov es,[batch] ;AN000; get batch segment
|
|
mov di,batfile ;AN000; get batch file name
|
|
push cs ;AN000; get local segment to DS
|
|
pop ds ;AN000;
|
|
mov dx,offset trangroup:combuf ;AN000; pass communications buffer
|
|
int 2fh ;AN000; call the shell
|
|
cmp al,shell_action ;AN000; does shell have a commmand?
|
|
pop ds ;AN000; restore DS
|
|
pop es ;AN000; restore ES
|
|
jz jdocom1 ;AN000; yes - go process command
|
|
|
|
PUSH DS ;G
|
|
INVOKE READBAT ; Continue BATCH
|
|
POP DS ;G
|
|
mov nullflag,0 ;G reset no command flag
|
|
TEST [BATCH],-1 ;G
|
|
JNZ JDOCOM1 ;G if batch still in progress continue
|
|
MOV BX,NEXT_BATCH ;G
|
|
CMP BX,0 ;G see if there is a new batch file
|
|
JZ JDOCOM1 ;G no - go do command
|
|
MOV BATCH,BX ;G get segment of next batch file
|
|
MOV NEXT_BATCH,0 ;G reset next batch
|
|
JDOCOM1:
|
|
PUSH CS ;G
|
|
POP DS ;G
|
|
JMP DoCom1 ; echoing already done
|
|
|
|
ISNOBAT:
|
|
CMP [SINGLECOM],0
|
|
JZ REGCOM
|
|
MOV SI,-1
|
|
CMP KSWITCHFLAG,0
|
|
JE NO_K_SWITCH
|
|
INC SI
|
|
MOV KSWITCHFLAG,0
|
|
NO_K_SWITCH:
|
|
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
|
|
;
|
|
; do NOT issue a trailing CRLF...
|
|
;
|
|
JMP DOCOM1
|
|
|
|
;
|
|
; We have a normal command.
|
|
; Printers are a bizarre quantity. Sometimes they are a stream and
|
|
; sometimes they aren't. At this point, we automatically close all spool
|
|
; files and turn on truncation mode.
|
|
;
|
|
|
|
REGCOM:
|
|
MOV AX,(ServerCall SHL 8) + 9
|
|
INT 21h
|
|
MOV AX,(ServerCall SHL 8) + 8
|
|
MOV DL,1
|
|
INT 21h
|
|
|
|
MOV DS,cs:[RESSEG]
|
|
ASSUME DS:RESGROUP
|
|
cmp byte ptr [SCS_FIRSTCOM],0
|
|
jnz first_inst ;this is the first instance
|
|
|
|
jmp DoReEnter
|
|
DRE_RET:
|
|
MOV DS,cs:[RESSEG]
|
|
ASSUME DS:RESGROUP
|
|
xor ax,ax
|
|
jmp short do_again
|
|
|
|
first_inst:
|
|
mov [SCS_PAUSE],0 ; yst 4-5-93
|
|
cmp [SCS_Is_First],1
|
|
jne cont_scs
|
|
mov [SCS_Is_First],0
|
|
|
|
SAVE <SI,BP>
|
|
xor si,si
|
|
xor bp,bp
|
|
mov al,2
|
|
mov ah,setdpb
|
|
int 21h ; resets the TSR bit
|
|
RESTORE <BP,SI>
|
|
xor ax,ax
|
|
jmp short do_again
|
|
|
|
cont_scs:
|
|
SAVE <AX,SI,BP>
|
|
xor si,si
|
|
xor bp,bp
|
|
mov al,2
|
|
mov ah,setdpb
|
|
int 21h ; resets the TSR bit
|
|
RESTORE <BP,SI,AX>
|
|
jnc cont_scs2
|
|
|
|
cont_tsr:
|
|
jmp tsr_loop
|
|
tsr_loop_ret:
|
|
jmp short cont_scs1
|
|
|
|
cont_scs2:
|
|
cmp byte ptr [scs_firsttsr],1
|
|
je cont_scs1
|
|
jmp short cont_tsr
|
|
|
|
cont_scs1:
|
|
; call free_con
|
|
|
|
MOV DS,cs:[RESSEG]
|
|
ASSUME DS:RESGROUP
|
|
mov ax,[retcode]
|
|
|
|
do_again:
|
|
ifdef NEC_98
|
|
jmp ClrFky
|
|
FKY_OFF DB 1Bh,'[>1h$' ;ESC sequence of FKY off
|
|
Clrfky: push ds
|
|
push cs
|
|
pop ds
|
|
push cx
|
|
push ax
|
|
push dx
|
|
mov cl,10H
|
|
mov ah,01H
|
|
mov dx,offset FKY_OFF
|
|
int 0DCH ;FKY off
|
|
pop dx
|
|
pop ax
|
|
pop cx
|
|
pop ds
|
|
endif ;NEC_98
|
|
MOV DS,cs:[RESSEG]
|
|
ASSUME DS:RESGROUP
|
|
push es
|
|
mov es,[envirseg]
|
|
mov [ENV_PTR_SEG],es
|
|
call GETENVSIZ
|
|
pop es
|
|
push cs
|
|
pop ds
|
|
ASSUME DS:TRANGROUP
|
|
mov [ENV_SIZE],cx
|
|
|
|
;; williamh - Jan 11 1993
|
|
;; nt expects 16bits exit code while DOS has only 8 bits
|
|
;; clear the high byte so that things won't go wrong
|
|
xor ah, ah
|
|
|
|
MOV [SCS_EXIT_CODE],ax
|
|
mov ah,19h
|
|
int 21h
|
|
xor ah,ah
|
|
mov [SCS_CUR_DRIVE], ax ; a= 0 , b = 1 etc
|
|
mov [CMD_SIZE],COMBUFLEN
|
|
MOV DX,OFFSET TRANGROUP:UCOMBUF
|
|
|
|
if 0
|
|
; Try to read interactive command line via DOSKey.
|
|
; If that fails, use DOS Buffered Keyboard Input.
|
|
|
|
mov ax,4810h ; AX = DOSKey Read Line function
|
|
int 2fh
|
|
or ax,ax
|
|
jz GotCom ; DOSKey gave us a command line
|
|
else
|
|
mov [CMD_PTR_SEG],ds
|
|
mov [CMD_PTR_OFF],dx
|
|
|
|
mov dx,OFFSET TRANGROUP:EXECPATH
|
|
mov [EXECPATH_SEG], ds
|
|
mov [EXECPATH_OFF], dx
|
|
mov [EXECPATH_SIZE], EXECPATHLEN
|
|
|
|
push es
|
|
mov es,cs:[RESSEG]
|
|
ASSUME es:RESGROUP
|
|
mov dx,word ptr es:[RES_RDRINFO]
|
|
mov word ptr ds:[SCS_RDRINFO],dx
|
|
mov dx,word ptr es:[RES_RDRINFO+2]
|
|
mov word ptr ds:[SCS_RDRINFO+2],dx
|
|
pop es
|
|
ASSUME ES:TRANGROUP
|
|
MOV DX,OFFSET TRANGROUP:ENV_PTR_SEG
|
|
|
|
|
|
CMDSVC SVC_CMDGETNEXTCMD ; DS:DX is the buffer
|
|
jnc run_cmd
|
|
|
|
; If carry is set that means our enviornment buffer was smaller. So get
|
|
; a big enough buffer and get the command again.
|
|
cmp ax,32*1024 ; Env size cannot be more than 32k.
|
|
jae op_fail
|
|
push ax ; the new size in bytes for env in bytes
|
|
invoke FREE_TPA
|
|
pop bx
|
|
MOV CL,4
|
|
SHR BX,CL ; Convert back to paragraphs
|
|
inc bx ; an extra para
|
|
push es
|
|
push ds
|
|
MOV DS,cs:[RESSEG]
|
|
ASSUME DS:RESGROUP
|
|
mov es,[envirseg]
|
|
pop ds
|
|
ASSUME DS:TRANGROUP
|
|
MOV CX,ES ;AN056; Get environment segment
|
|
ADD CX,BX ;AN056; Add in size of environment
|
|
ADD CX,020H ;AN056; Add in some TPA
|
|
MOV AX,CS ;AN056; Get the transient segment
|
|
CMP CX,AX ;AN056; Are we hitting the transient?
|
|
JNB blk_xxx ;AN056; Yes - don't do it!!!
|
|
|
|
push bx
|
|
MOV AH,SETBLOCK
|
|
INT 21h
|
|
pop bx
|
|
jnc blk_xxx
|
|
|
|
mov ah,ALLOC
|
|
int 21h
|
|
jc blk_xxx
|
|
push ax
|
|
|
|
mov ah,DEALLOC
|
|
int 21h
|
|
|
|
pop ax
|
|
push ds
|
|
MOV DS,cs:[RESSEG]
|
|
ASSUME DS:RESGROUP
|
|
mov [envirseg],ax
|
|
pop ds
|
|
ASSUME DS:TRANGROUP
|
|
clc
|
|
blk_xxx:
|
|
lahf
|
|
push ax
|
|
MOV ES,cs:[RESSEG]
|
|
invoke ALLOC_TPA
|
|
pop ax
|
|
sahf
|
|
JC op_fail1
|
|
pop es
|
|
xor ax,ax ; error code zero, its important
|
|
jmp do_again
|
|
op_fail1:
|
|
pop es
|
|
op_fail:
|
|
mov ax,error_not_enough_memory
|
|
jmp do_again
|
|
|
|
run_cmd:
|
|
push es
|
|
mov es,cs:[RESSEG]
|
|
ASSUME es:RESGROUP
|
|
mov ax,word ptr ds:[SCS_RDRINFO]
|
|
mov word ptr es:[RES_RDRINFO],ax
|
|
mov ax,word ptr ds:[SCS_RDRINFO+2]
|
|
mov word ptr es:[RES_RDRINFO+2],ax
|
|
mov ax,word ptr ds:[SCS_BATSTATUS]
|
|
mov byte ptr es:[RES_BATSTATUS],al
|
|
pop es
|
|
ASSUME ES:TRANGROUP
|
|
test [SCS_STD_HANDLE],ALL_HANDLES
|
|
jz no_rdr
|
|
test [SCS_STD_HANDLE],MASK_STDIN
|
|
jz scs_std_out
|
|
xor cx,cx ; CX = HANDLE_STDIN
|
|
call alloc_con
|
|
jnc scs_std_out
|
|
rdr_err:
|
|
call free_con
|
|
mov ax,error_not_enough_memory
|
|
jmp do_again
|
|
|
|
scs_std_out:
|
|
; Make Sure Stdout is checked before stderr. Its very important.
|
|
test [SCS_STD_HANDLE],MASK_STDOUT
|
|
jz scs_std_err
|
|
mov cx,HANDLE_STDOUT
|
|
call alloc_con
|
|
jc rdr_err
|
|
|
|
scs_std_err:
|
|
test [SCS_STD_HANDLE],MASK_STDERR
|
|
jz no_rdr
|
|
mov cx,HANDLE_STDERR
|
|
call alloc_con
|
|
jc rdr_err
|
|
|
|
no_rdr:
|
|
ifdef NEC_98
|
|
push ds
|
|
push cx
|
|
push ax
|
|
push dx
|
|
|
|
CMDSVC SVC_GETCURSORPOS ;gets bios cursor position
|
|
;now dx=offset on TEXT VRAM
|
|
mov ax,dx
|
|
mov cl,160
|
|
div cl
|
|
mov dh,al
|
|
xor dl,dl
|
|
mov cl,10h
|
|
mov ah,03h
|
|
int 0DCH ;set cursor position for DOS
|
|
|
|
jmp DspFky
|
|
FKY_ON DB 1Bh,'[>1l$' ;ESC sequence of FKY on
|
|
Dspfky: push cs
|
|
pop ds
|
|
mov cl,10H
|
|
mov ah,01H
|
|
mov dx,offset FKY_ON
|
|
int 0DCH ;FKY on
|
|
|
|
pop dx
|
|
pop ax
|
|
pop cx
|
|
pop ds
|
|
endif ;NEC_98
|
|
mov ah,GetSetCdPg
|
|
mov al,1
|
|
int 21h
|
|
jc cdpg_done
|
|
cmp bx,[SCS_CODEPAGE]
|
|
jz cdpg_done
|
|
|
|
mov ah,NLSFUNC ; see if NLSFUNC installed
|
|
mov al,0 ;
|
|
int 2fh ;
|
|
cmp al,NLSFUNC_installed ;
|
|
jnz no_nlsf_msg ; NO NLSFUNC ; Print message
|
|
; jz got_nls ; Yes - continue
|
|
; mov dx,offset trangroup:NLSFUNC_ptr ; no - set up error message
|
|
; jmp short cp_error ; error exit
|
|
|
|
mov bx,[SCS_CODEPAGE] ;SCS Code page
|
|
mov ah,getsetcdpg ;set global code page function
|
|
mov al,set_global_cp ;minor - set
|
|
int 21h
|
|
jnc cdpg_done ;no error - exit
|
|
nlsf_failed:
|
|
; BUGBUG Sudeepb 28-Apr-1992 Putup a message saying NLSFunc failed
|
|
no_nlsf_msg:
|
|
; BUGBUG Sudeepb 28-Apr-1992 Putup a message saying NLSFunc not installed
|
|
|
|
cdpg_done:
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; (YST) 08-Jan-1993 Checking and installing 16-bit KEYB.COM ;;
|
|
;; ;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
jmp YST_beg
|
|
|
|
;; Data for KB16
|
|
|
|
KEY_LINE db 128 dup (0) ; "d:\nt\system32\kb16.com", 0
|
|
YST_ARG db 128 dup (0) ; 32, " XX,,d:\nt\system32\keyboard.sys", 0DH
|
|
|
|
|
|
YPAR dw 0
|
|
dd 0
|
|
dw 005ch, 0
|
|
dw 006ch, 0
|
|
|
|
KEEP_SS dw 0
|
|
KEEP_SP dw 0
|
|
|
|
YST_beg:
|
|
|
|
SAVE <BX, ES, DS> ; save all regs for INT 2FH
|
|
|
|
mov ax, CHECK_KEYB16 ; see if KEYB16 installed
|
|
int 2fh
|
|
xor dx,dx
|
|
cmp al, KEYB16_installed
|
|
jne keyb_cont ; KEYB16 not installed, DX == 0
|
|
inc dx ; installed DX == 1
|
|
|
|
keyb_cont:
|
|
RESTORE <DS, ES, BX>
|
|
|
|
push ds
|
|
push cs
|
|
pop ds
|
|
|
|
mov si, offset KEY_LINE ; name of KB16.COM
|
|
mov cx, offset YST_ARG ; command line
|
|
|
|
CMDSVC SVC_GETKBDLAYOUT ; Call 32-bit API for checking
|
|
; and installing correct layout
|
|
or dx,dx ; if DX != 0 after BOP then we need
|
|
pop ds ; to install 16-bit KEYB.COM
|
|
jnz run_keyb
|
|
|
|
jmp End_keyb ; No installation of KB16.COM
|
|
|
|
run_keyb:
|
|
|
|
;; This part run KB16.COM
|
|
|
|
SAVE <DS, BX>
|
|
|
|
PUSH ES ; free TPA for running KB16
|
|
MOV ES,[TRAN_TPA]
|
|
MOV AH,DEALLOC
|
|
INT 21h ; Now running in "free" space
|
|
|
|
push cs
|
|
pop ds
|
|
push cs
|
|
pop es
|
|
|
|
mov dx, offset KEY_LINE ; file name
|
|
mov YPAR+0, 0000H ; keep current enviroment
|
|
mov YPAR+2, offset YST_ARG ; arguments (options) for KB16.COM
|
|
mov YPAR+4, ds
|
|
mov bx, offset YPAR
|
|
|
|
mov KEEP_SS, ss ; Peter Norton suggests to keep
|
|
mov KEEP_SP, sp ; SS and SP
|
|
|
|
mov ah, 4bh
|
|
xor al, al
|
|
|
|
int 21h ; RUN!
|
|
|
|
mov ss, cs:KEEP_SS ; Restore SS and SP
|
|
mov sp, cs:KEEP_SP
|
|
|
|
POP ES
|
|
|
|
SAVE <BP> ; We need to restore TSR bit
|
|
xor si,si ; for running next app.
|
|
xor bp,bp ; use "undocumented" call.
|
|
mov al,2
|
|
mov ah,setdpb
|
|
int 21h ; resets the TSR bit
|
|
RESTORE <BP>
|
|
|
|
|
|
; Allocate transient again after runnig KB16.
|
|
; Copied from TBATCH.ASM
|
|
; Modify AX,BX,DX,flags
|
|
;
|
|
|
|
ASSUME DS:TRANGROUP,ES:RESGROUP
|
|
|
|
PUSH ES
|
|
MOV ES,cs:[RESSEG]
|
|
MOV BX,0FFFFH ; Re-allocate the transient
|
|
MOV AH,ALLOC
|
|
INT 21h
|
|
PUSH BX ; Save size of block
|
|
MOV AH,ALLOC
|
|
INT 21h
|
|
;
|
|
; Attempt to align TPA on 64K boundary
|
|
;
|
|
POP BX ; Restore size of block
|
|
MOV [RES_TPA], AX ; Save segment to beginning of block
|
|
MOV [TRAN_TPA], AX
|
|
;
|
|
; Is the segment already aligned on a 64K boundary
|
|
;
|
|
MOV DX, AX ; Save segment
|
|
AND AX, 0FFFH ; Test if above boundary
|
|
JNZ Calc_TPA
|
|
MOV AX, DX
|
|
AND AX, 0F000H ; Test if multiple of 64K
|
|
JNZ NOROUND
|
|
|
|
Calc_TPA:
|
|
MOV AX, DX
|
|
AND AX, 0F000H
|
|
ADD AX, 01000H ; Round up to next 64K boundary
|
|
JC NOROUND ; Memory wrap if carry set
|
|
;
|
|
; Make sure that new boundary is within allocated range
|
|
;
|
|
MOV DX, [RES_TPA]
|
|
ADD DX, BX ; Compute maximum address
|
|
CMP DX, AX ; Is 64K address out of range?
|
|
JB NOROUND
|
|
;
|
|
; Make sure that we won't overwrite the transient
|
|
;
|
|
MOV BX, CS ; CS is beginning of transient
|
|
CMP BX, AX
|
|
JB NOROUND
|
|
;
|
|
; The area from the 64K boundary to the beginning of the transient must
|
|
; be at least 64K.
|
|
;
|
|
SUB BX, AX
|
|
CMP BX, 4096 ; Size greater than 64K?
|
|
JAE ROUNDDONE
|
|
|
|
NOROUND:
|
|
MOV AX, [RES_TPA]
|
|
|
|
ROUNDDONE:
|
|
MOV [LTPA],AX ; Re-compute everything
|
|
MOV [TPA],AX
|
|
MOV BX,AX
|
|
MOV AX,CS
|
|
SUB AX,BX
|
|
PUSH BX
|
|
MOV BX,16
|
|
MUL BX
|
|
POP BX
|
|
OR DX,DX
|
|
JZ SAVSIZ2
|
|
MOV AX,-1
|
|
|
|
SAVSIZ2:
|
|
;
|
|
; AX is the number of bytes free in the buffer between the resident and the
|
|
; transient with a maximum of 64K-1. We round this down to a multiple of 512.
|
|
;
|
|
CMP AX,512
|
|
JBE GotSize1
|
|
AND AX,0FE00h ; NOT 511 = NOT 1FF
|
|
|
|
GotSize1:
|
|
MOV [BYTCNT],AX
|
|
POP ES
|
|
|
|
|
|
; End Alloc_TPA
|
|
|
|
|
|
RESTORE <BX, DS>
|
|
|
|
CMDSVC SVC_CMDINITCONSOLE ; make sure console is turned on
|
|
|
|
End_keyb:
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; End of (YST) 08-Jan-1993 Checking and installing 16-bit KEYB.COM ;;
|
|
;; ;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
mov dx,[SCS_CUR_DRIVE]
|
|
mov [curdrv],dl
|
|
mov ah,0eh
|
|
int 21h
|
|
push cs
|
|
pop ds
|
|
MOV DX,OFFSET TRANGROUP:UCOMBUF
|
|
|
|
endif
|
|
|
|
GotCom:
|
|
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
|
|
|
|
;---------------
|
|
|
|
transpace segment
|
|
extrn arg:byte ; the arg structure!
|
|
transpace ends
|
|
;---------------
|
|
|
|
|
|
DOCOM:
|
|
; INVOKE CRLF2
|
|
|
|
DOCOM1:
|
|
INVOKE PRESCAN ; Cook the input buffer
|
|
JZ NOPIPEPROC
|
|
JMP PIPEPROCSTRT ; Fire up the pipe
|
|
|
|
nullcomj:
|
|
jmp nullcom
|
|
|
|
NOPIPEPROC:
|
|
invoke parseline
|
|
jnc OkParse ; user error? or maybe we goofed?
|
|
|
|
BadParse:
|
|
PUSH CS
|
|
POP DS
|
|
MOV DX,OFFSET TRANGROUP:BADNAM_ptr
|
|
INVOKE std_eprintf
|
|
JMP TCOMMAND
|
|
|
|
OkParse:
|
|
test arg.argv[0].argflags, MASK wildcard
|
|
jnz BadParse ; ambiguous commands not allowed
|
|
cmp arg.argvcnt, 0 ; there WAS a command, wasn't there?
|
|
jz nullcomj
|
|
cmp arg.argv[0].arglen, 0 ; probably an unnecessary check...
|
|
jz nullcomj ; guarantees argv[0] at least x<NULL>
|
|
|
|
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 21h
|
|
mov BX, arg.argv[0].argpointer
|
|
cmp WORD PTR [BX], 05c5ch ; leading "\\" means UNC name
|
|
je IsUncName
|
|
cmp BYTE PTR [BX+1],':' ; was a drive specified?
|
|
jne short drvgd ; no, use default of zero...
|
|
|
|
mov DL, BYTE PTR [BX] ; pick-up drive letter
|
|
and DL, NOT 20H ; uppercase it
|
|
sub DL, capital_A ; convert it to a drive number, A=0
|
|
|
|
CMP AL,-1 ; See what PARSE said about our drive letter.
|
|
JZ drvbadj2 ; It was invalid.
|
|
|
|
IsUncName:
|
|
mov DI, arg.argv[0].argstartel
|
|
cmp BYTE PTR [DI], 0 ; is there actually a command there?
|
|
jnz drvgd ; if not, we have: "d:", "d:\", "d:/"
|
|
jmp setdrv ; and set drive to new drive spec
|
|
|
|
drvbadj2:
|
|
jmp drvbad
|
|
|
|
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,8
|
|
SUB AL,CL
|
|
MOV [IDLEN],AL ; IDLEN is truly the length
|
|
MOV DI,81H
|
|
PUSH SI
|
|
|
|
mov si, OFFSET TRANGROUP:COMBUF+2 ; Skip over all leading delims
|
|
invoke scanoff
|
|
;SR;
|
|
; We are going to skip over the first char always. The logic is that the
|
|
;command tail can never start from the first character. The code below is
|
|
;trying to figure out the command tail and copy it to the command line
|
|
;buffer in the PSP. However, if the first character happens to be a switch
|
|
;character and the user given command line is a full 128 bytes, we try to
|
|
;copy 128 bytes to the PSP while it can take only 127 chars. This extra
|
|
;char overwrites the code and leads to a crash on future commands.
|
|
;
|
|
|
|
inc si
|
|
|
|
do_skipcom:
|
|
lodsb ; move command line pointer over
|
|
invoke delim ; pathname -- have to do it ourselves
|
|
jz do_skipped ; 'cause parse_file_descriptor is dumb
|
|
cmp AL, 0DH ; can't always depend on argv[0].arglen
|
|
jz do_skipped ; to be the same length as the user-
|
|
cmp AL, [SWITCHAR] ; specified command string
|
|
jnz do_skipcom
|
|
|
|
do_skipped:
|
|
dec SI
|
|
; jarbats 11-20-2000
|
|
; failing to decrease SI results in missing leading space for command tail
|
|
; which upsets many old dos apps which assume there is a space at the beginning and start at the second char
|
|
;do_skipped1:
|
|
XOR CX,CX
|
|
|
|
COMTAIL:
|
|
LODSB
|
|
STOSB ; Move command tail to 80H
|
|
CMP AL,13
|
|
LOOPNZ COMTAIL
|
|
DEC DI
|
|
MOV BP,DI
|
|
NOT CL
|
|
MOV BYTE PTR DS:[80H],CL
|
|
POP SI
|
|
|
|
;-----
|
|
; Some of these comments are sadly at odds with this brave new code.
|
|
;-----
|
|
; If the command has 0 parameters must check here for
|
|
; any switches that might be present.
|
|
; SI -> first character after the command.
|
|
|
|
mov DI, arg.argv[0].argsw_word
|
|
mov [COMSW], DI ; ah yes, the old addressing mode problem...
|
|
mov SI, arg.argv[1 * SIZE argv_ele].argpointer ; s = argv[1];
|
|
OR SI,SI ; if (s == NULL)
|
|
JNZ DoParse
|
|
MOV SI,BP ; s = bp; (buffer end)
|
|
|
|
DoParse:
|
|
MOV DI,FCB
|
|
MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H
|
|
INT 21h
|
|
MOV [PARM1],AL ; Save result of parse
|
|
|
|
mov DI, arg.argv[1*SIZE argv_ele].argsw_word
|
|
mov [ARG1S], DI
|
|
mov SI, arg.argv[2*SIZE argv_ele].argpointer ; s = argv[2];
|
|
OR SI,SI ; if (s == NULL)
|
|
JNZ DoParse2
|
|
MOV SI,BP ; s = bp; (bufend)1
|
|
|
|
DoParse2:
|
|
MOV DI,FCB+10H
|
|
MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 01H
|
|
INT 21h ; Parse file name
|
|
MOV [PARM2],AL ; Save result
|
|
|
|
mov DI, arg.argv[2*SIZE argv_ele].argsw_word
|
|
mov [ARG2S], DI
|
|
mov DI, arg.argv[0].argsw_word
|
|
not DI ; ARGTS doesn't include the flags
|
|
and DI, arg.argswinfo ; from COMSW...
|
|
mov [ARGTS], DI
|
|
|
|
MOV AL,[IDLEN]
|
|
MOV DL,[SPECDRV]
|
|
or DL, DL ; if a drive was specified...
|
|
jnz externalj1 ; it MUST be external, by this time
|
|
dec al ; (I don't know why -- old code did it)
|
|
jmp fndcom ; otherwise, check internal com table
|
|
|
|
externalj1:
|
|
jmp external
|
|
|
|
nullcom:
|
|
mov [EXECPATH_SIZE], 0
|
|
MOV DS,cs:[RESSEG]
|
|
ASSUME DS:RESGROUP
|
|
TEST [BATCH], -1 ;G Are we in a batch file?
|
|
JZ nosetflag ;G only set flag if in batch
|
|
mov nullflag,nullcommand ;G set flag to indicate no command
|
|
|
|
nosetflag:
|
|
CMP [SINGLECOM],-1
|
|
JZ EXITJ
|
|
JMP GETCOM
|
|
|
|
EXITJ:
|
|
JMP $EXITPREP
|
|
|
|
IF IBM
|
|
include vector.inc
|
|
include pdb.inc
|
|
include arena.inc
|
|
include mshalo.asm
|
|
ENDIF
|
|
|
|
std_invalid macro
|
|
mov ax,0ffffh
|
|
push ax
|
|
push ax
|
|
endm
|
|
|
|
std_valid macro
|
|
push bx
|
|
push cx
|
|
endm
|
|
|
|
CleanForStd macro
|
|
add sp,12
|
|
endm
|
|
|
|
DoReEnter:
|
|
ASSUME DS:RESGROUP
|
|
|
|
cmp byte ptr [scs_reentered],3
|
|
jne reent_chk
|
|
|
|
; Control comes here after command /z ran a non-dos binary and
|
|
; we re-entered. We just make scs_reentered as 2 indicating that on next
|
|
; time we need to return the exit code to 32bit side.
|
|
|
|
mov byte ptr [scs_reentered],2
|
|
jmp reent
|
|
|
|
reent_chk:
|
|
cmp byte ptr [scs_reentered],2
|
|
jne reent_cont
|
|
jmp retcode32
|
|
|
|
reent_cont:
|
|
cmp byte ptr [scs_reentered],0
|
|
je exec_comspec
|
|
jmp reent_ret
|
|
|
|
; Control comes here when we have to exec either command.com or
|
|
; cmd.exe. This decision depends on scs_cmdprompt. Here we
|
|
; mark scs_reentered state as 1 indicating on return to handle
|
|
; exit code.
|
|
|
|
exec_comspec:
|
|
|
|
mov byte ptr [scs_reentered],1
|
|
cmp byte ptr [scs_cmdprompt],Prompt32
|
|
je do32bitprompt
|
|
mov al,Start16 ; parameter to put prompt
|
|
mov ah,FOR_SHELLOUT
|
|
call Do16BitPrompt ; ds is resseg here on return its transseg
|
|
or al,al ; return al=0 to run 16bit binary al=1 getnextvdmcommand
|
|
jz dos_only
|
|
jmp reent
|
|
dos_only:
|
|
jmp GotCom ; go run through int21/exec
|
|
|
|
do32BitPrompt:
|
|
SAVE <bp,bx,si>
|
|
xor bx,bx
|
|
mov si,bx
|
|
mov bp,bx
|
|
mov ax,5303h
|
|
int 21h
|
|
jnc st_stdin
|
|
std_invalid
|
|
jmp short go_stdout
|
|
st_stdin:
|
|
std_valid
|
|
go_stdout:
|
|
mov bx,1
|
|
mov ax,5303h
|
|
int 21h
|
|
jnc st_stdout
|
|
std_invalid
|
|
jmp short go_stderr
|
|
st_stdout:
|
|
std_valid
|
|
go_stderr:
|
|
mov bx,2
|
|
mov ax,5303h
|
|
int 21h
|
|
jnc st_stderr
|
|
std_invalid
|
|
jmp short std_done
|
|
st_stderr:
|
|
std_valid
|
|
std_done:
|
|
mov bp,sp
|
|
push es
|
|
mov es,[envirseg]
|
|
mov ah,19h
|
|
int 21h
|
|
CMDSVC SVC_EXECCOMSPEC32
|
|
pop es
|
|
mov bp,ax
|
|
lahf
|
|
CleanForStd
|
|
sahf
|
|
mov ax,bp
|
|
RESTORE <si,bx,bp>
|
|
|
|
jc reent
|
|
|
|
jmp reent_exit
|
|
|
|
reent_ret:
|
|
; ds is already set to RESSEG
|
|
cmp byte ptr [scs_cmdprompt],Prompt32
|
|
je retcode32
|
|
mov al,return16
|
|
mov ah,FOR_SHELLOUT
|
|
call Do16BitPrompt ; ds = resseg , on return its transseg
|
|
or al,al ; return al=0 to run 16bit binary al=1 getnextvdmcommand
|
|
jnz reent
|
|
jmp dos_only
|
|
|
|
retcode32:
|
|
mov dx,ds:[retcode]
|
|
mov ah,19h
|
|
int 21h ; al = cur drive
|
|
mov cx,word ptr ds:[RES_RDRINFO]
|
|
mov bx,word ptr ds:[RES_RDRINFO+2] ; bx:cx - rdrinfo
|
|
CMDSVC SVC_RETURNEXITCODE
|
|
mov ds:[retcode],0
|
|
jnc reent_exit
|
|
reent:
|
|
push cs
|
|
pop ds
|
|
assume ds:trangroup
|
|
mov [scs_tsrexit],0
|
|
jmp DRE_RET
|
|
|
|
reent_exit:
|
|
ASSUME DS:RESGROUP
|
|
push ax
|
|
mov ax,(multdos shl 8 or message_2f);AN060; reset parse message pointers
|
|
mov dl,set_critical_msg ;AN000; set up critical error message address
|
|
mov di,crit_msg_off ;AN000; old offset of critical messages
|
|
mov es,crit_msg_seg ;AN000; old segment of critical messages
|
|
int 2fh ;AN000; go set it
|
|
|
|
push cs
|
|
pop ds
|
|
assume ds:trangroup ;AN000;
|
|
|
|
; Restore user directory if the restore flag is set. RestUDir1 checks for
|
|
; this, restores user dir if flag is set and resets the flag.
|
|
|
|
invoke RestUDir1 ;restore user dir if needed ;M040
|
|
MOV ES,cs:[RESSEG]
|
|
|
|
assume es:resgroup
|
|
|
|
MOV AX,[PARENT]
|
|
MOV WORD PTR ES:[PDB_Parent_PID],AX
|
|
MOV AX,WORD PTR OldTerm
|
|
MOV WORD PTR ES:[PDB_Exit],AX
|
|
MOV AX,WORD PTR OldTerm+2
|
|
MOV WORD PTR ES:[PDB_Exit+2],AX
|
|
|
|
PUSH ES
|
|
MOV ES,[TRAN_TPA]
|
|
MOV AH,DEALLOC
|
|
INT 21h ; Now running in "free" space
|
|
POP ES
|
|
|
|
pop ax
|
|
MOV AH,Exit
|
|
INT 21h
|
|
|
|
; Entry al = Start16 means put the command.com prompt, get the command
|
|
; return16 means return the exit code if needed
|
|
; ah = FOR_SHELLOUT means came from shellout code (DoReEnter)
|
|
; ah = FOR_TSR means came from TSR (tsr_loop)
|
|
;
|
|
; Exit al = 0 means run 16bit binary
|
|
; al = 1 means do getnextvdmcommand
|
|
; if came with FOR_TSR, then additionaly
|
|
; ah = 1 means returning on exit command
|
|
; ah = 0 means otherwise
|
|
|
|
Do16BitPrompt:
|
|
push es
|
|
push ax
|
|
mov es,cs:[RESSEG] ; es is resident group
|
|
ASSUME ES:resgroup
|
|
PUSH CS
|
|
POP DS ; Need local segment to point to buffer
|
|
assume ds:trangroup
|
|
cmp al,Start16
|
|
ifdef DBCS
|
|
je @F
|
|
jmp d16_ret
|
|
@@:
|
|
else ; !DBCS
|
|
jne d16_ret
|
|
endif ; !DBCS
|
|
|
|
d16_loop:
|
|
ifdef DBCS
|
|
;;; williamh Sept 24 1993, removed it. Not necessary to show two line feed
|
|
;;; for every command.
|
|
;;; yasuho 12/9/93 It is necessary. for example, if previous command
|
|
;;; didn't follow CR+LF before terminate, prompt will show on the strange
|
|
;;; position.
|
|
endif ; DBCS
|
|
INVOKE CRLF2
|
|
INVOKE PRINT_PROMPT ; put the prompt
|
|
ifdef DBCS ;; this should go to US build also
|
|
;; reset the title
|
|
xor al, al
|
|
CMDSVC SVC_SETWINTITLE
|
|
endif ; DBCS
|
|
MOV DX,OFFSET TRANGROUP:UCOMBUF
|
|
|
|
mov ah,STD_CON_STRING_INPUT ; AH = Buffered Keyboard Input
|
|
int 21h ; call DOS
|
|
ifdef DBCS_NT31J
|
|
;; special case for CR was added the original source.
|
|
;; this code doesn't need. 04/07/94 (hiroh)
|
|
;; #3920: CR+LFs are needed when using 32bit command
|
|
;; 12/9/93 yasuho
|
|
;; not necessary CR+LF if nothing to do
|
|
push bx
|
|
mov bx, dx
|
|
cmp byte ptr [bx + 1], 0 ; only CR ?
|
|
pop bx
|
|
je @F ; yes. no neccessary CRLF
|
|
INVOKE CRLF2
|
|
@@:
|
|
endif ; DBCS_NT31J
|
|
|
|
push si
|
|
mov si,dx
|
|
inc si
|
|
inc si
|
|
INVOKE SCANOFF ; eat leading delimeters
|
|
|
|
cmp byte ptr ds:[si],0dh ; special case CR
|
|
jne d16_gotcom
|
|
pop si
|
|
jmp d16_loop
|
|
|
|
d16_gotcom:
|
|
ifdef DBCS ;; this should go to US build also
|
|
;; update the new command to the title
|
|
mov al, 1
|
|
CMDSVC SVC_SETWINTITLE
|
|
endif ; DBCS
|
|
INVOKE CRLF2
|
|
call check_command ; check for exit and cd
|
|
pop si
|
|
jnc d16_run
|
|
|
|
or al,al
|
|
ifdef DBCS
|
|
jnz @F
|
|
jmp d16_exit
|
|
@@:
|
|
else ; !DBCS
|
|
jz d16_exit
|
|
endif ; !DBCS
|
|
|
|
d16_dosonly:
|
|
mov byte ptr es:[scs_prompt16],0
|
|
pop ax
|
|
xor ax,ax ; go run the command
|
|
pop es
|
|
ret
|
|
|
|
d16_run:
|
|
cmp byte ptr es:[scs_dosonly], DOSONLY_YES
|
|
je d16_dosonly
|
|
|
|
push es
|
|
push bp
|
|
push si
|
|
mov ax,0ffffh
|
|
push ax ; no standard handle to pass
|
|
push ax
|
|
push ax
|
|
push ax
|
|
push ax
|
|
push ax
|
|
mov bp,sp ; ss:bp is standard handles
|
|
mov es,es:[envirseg]
|
|
mov si,dx
|
|
add si,2 ; first two bytes are the count, after that real command
|
|
mov ah,19h
|
|
int 21h ; al = cur drive
|
|
ifdef NEC_98
|
|
jmp Clrfky2
|
|
FKY_OFF2 DB 1Bh,'[>1h$' ;ESC sequence of FKY off
|
|
Clrfky2: push ds
|
|
push cs
|
|
pop ds
|
|
push cx
|
|
push ax
|
|
push dx
|
|
mov cl,10H
|
|
mov ah,01H
|
|
mov dx,offset FKY_OFF2
|
|
int 0DCH ;FKY off
|
|
pop dx
|
|
pop ax
|
|
pop cx
|
|
pop ds
|
|
endif ;NEC_98
|
|
mov ah,1 ; do cmd /c
|
|
CMDSVC SVC_CMDEXEC ; Exec through cmd
|
|
ifdef NEC_98
|
|
pushf
|
|
push ds
|
|
push cx
|
|
push ax
|
|
push dx
|
|
|
|
CMDSVC SVC_GETCURSORPOS ;gets bios cursor position
|
|
;now dx=offset on TEXT VRAM
|
|
mov ax,dx
|
|
mov cl,160
|
|
div cl
|
|
mov dh,al
|
|
xor dl,dl
|
|
mov cl,10h
|
|
mov ah,03h
|
|
int 0DCH ;set cursor position for DOS
|
|
|
|
jmp Dspfky2
|
|
FKY_ON2 DB 1Bh,'[>1l$' ;ESC sequence of FKY on
|
|
Dspfky2: push cs
|
|
pop ds
|
|
mov cl,10H
|
|
mov ah,01H
|
|
mov dx,offset FKY_ON2
|
|
int 0DCH ;FKY on
|
|
|
|
pop dx
|
|
pop ax
|
|
pop cx
|
|
pop ds
|
|
popf
|
|
endif ;NEC_98
|
|
lahf
|
|
add sp,12 ; recover std handle space
|
|
pop si
|
|
pop bp
|
|
pop es
|
|
sahf
|
|
|
|
ifndef NEC_98
|
|
jnc d16_loop ; command completed, go put the prompt
|
|
else ;NEC_98
|
|
jc @F
|
|
jmp d16_loop
|
|
@@:
|
|
endif ;NEC_98
|
|
|
|
; carry set means re-entered
|
|
d16_retback:
|
|
mov byte ptr es:[scs_prompt16],1 ; mark that on return we have
|
|
; to go to 32bit with retcode
|
|
pop ax
|
|
mov ax,1 ; go do getnextvdmcommand
|
|
pop es
|
|
ret
|
|
|
|
d16_ret:
|
|
cmp byte ptr es:[scs_prompt16],0 ; mark 0 to mean to come back
|
|
; and put prompt fro next command
|
|
ifdef DBCS
|
|
jne @F
|
|
jmp d16_loop
|
|
@@:
|
|
else ; !DBCS
|
|
je d16_loop
|
|
endif ; !DBCS
|
|
|
|
|
|
d16_return32:
|
|
push dx
|
|
mov dx,es:[retcode]
|
|
mov ah,19h
|
|
int 21h ; al = cur drive
|
|
mov cx,word ptr es:[RES_RDRINFO]
|
|
mov bx,word ptr es:[RES_RDRINFO+2] ; bx:cx - rdrinfo
|
|
CMDSVC SVC_RETURNEXITCODE
|
|
pop dx
|
|
mov es:[retcode],0
|
|
jc d16_retback
|
|
mov byte ptr es:[scs_prompt16],0
|
|
jmp d16_loop
|
|
|
|
|
|
d16_exit:
|
|
; exit command was given, turn off the lights
|
|
|
|
pop ax
|
|
cmp ah,FOR_TSR
|
|
je d16_exittsr
|
|
jmp reent_exit
|
|
|
|
d16_exittsr:
|
|
mov ah,1
|
|
pop es
|
|
ret
|
|
|
|
|
|
; check if the typed command is one of the commands in NT_INTRL_CMND, if
|
|
; so return carry set plus al = 0 if the command was "exit".
|
|
;
|
|
; input ds:si is the command buffer
|
|
; si can be trashed.
|
|
|
|
check_command:
|
|
|
|
SAVE <CX,DI,ES>
|
|
|
|
cmp byte ptr ds:[si+1],':' ; special case drive change i.e C:
|
|
jne cc_0
|
|
mov al,byte ptr ds:[si+2]
|
|
cmp al,0dh ; DELIM for some reason does'nt
|
|
je ok_delim ; include 0d
|
|
invoke DELIM
|
|
jnz no_match
|
|
ok_delim:
|
|
mov al,1 ; Not exit command
|
|
ok_xt:
|
|
stc ; Carry means command found
|
|
jmp short cc_ret
|
|
|
|
no_match:
|
|
clc ; Carry clear, command not found
|
|
cc_ret:
|
|
RESTORE <ES,DI,CX>
|
|
ret
|
|
|
|
cc_0:
|
|
push si
|
|
xor cx,cx
|
|
|
|
; Convert the source string to upper case and get the length
|
|
cc_1:
|
|
mov al,byte ptr ds:[si]
|
|
invoke DELIM
|
|
jz go_look
|
|
invoke MOREDELIM
|
|
jz go_look
|
|
|
|
INVOKE UPCONV
|
|
mov byte ptr ds:[si],al
|
|
inc si
|
|
inc cx
|
|
jmp short cc_1
|
|
|
|
go_look:
|
|
pop si
|
|
jcxz no_match ; zero length, go fail
|
|
mov di, OFFSET TRANGROUP:NT_INTRNL_CMND
|
|
push cs
|
|
pop es
|
|
|
|
; search through the commands in the table
|
|
cc_5:
|
|
push si
|
|
push di
|
|
push cx
|
|
cmp cl, byte ptr es:[di]
|
|
jne try_next
|
|
inc di
|
|
repz cmpsb
|
|
jnz try_next
|
|
jmp short cc_found
|
|
|
|
try_next:
|
|
pop cx
|
|
pop di
|
|
pop si
|
|
mov al,byte ptr es:[di]
|
|
or al,al
|
|
jz no_match
|
|
xor ah,ah
|
|
add ax,di
|
|
mov di,ax
|
|
add di,2
|
|
jmp short cc_5
|
|
|
|
cc_found:
|
|
mov al, byte ptr es:[di] ; Is it exit command
|
|
pop cx
|
|
pop di
|
|
pop si
|
|
jmp short ok_xt
|
|
|
|
;
|
|
; Input: AL is character to classify
|
|
; Output: Z set if delimiter
|
|
; NZ set otherwise
|
|
; Registers modified: none
|
|
;
|
|
|
|
MOREDELIM:
|
|
cmp al,0dh
|
|
retz
|
|
cmp al,'/'
|
|
retz
|
|
cmp al,'\'
|
|
retz
|
|
cmp al,'.'
|
|
retz
|
|
cmp al,'<'
|
|
retz
|
|
cmp al,'>'
|
|
retz
|
|
cmp al,'|'
|
|
retz
|
|
cmp al,'"'
|
|
retz
|
|
cmp al,'+'
|
|
retz
|
|
cmp al,':'
|
|
retz
|
|
cmp al,';'
|
|
retz
|
|
cmp al,'['
|
|
retz
|
|
cmp al,']'
|
|
return
|
|
|
|
|
|
|
|
free_con:
|
|
push ds
|
|
MOV DS,cs:[RESSEG]
|
|
ASSUME DS:RESGROUP
|
|
xor bx,bx ; BX = handle = 0
|
|
mov cx,Io_Save ; CX = original stdin, stdout
|
|
mov dx,word ptr ds:Pdb_Jfn_Table ; DX = current stdin, stdout
|
|
cmp cl,dl
|
|
je Chk1 ; stdin matches
|
|
mov ah,CLOSE
|
|
int 21h ; close stdin
|
|
mov ds:Pdb_Jfn_Table,cl ; restore stdin
|
|
Chk1:
|
|
inc bx ; BX = handle = 1
|
|
cmp ch,dh
|
|
je Chk2 ; stdout matches
|
|
mov ah,CLOSE
|
|
int 21h ; close stdout
|
|
mov ds:Pdb_Jfn_Table+1,ch ; restore stdout
|
|
Chk2:
|
|
inc bx ; BX = handle = 2
|
|
mov dl,byte ptr ds:[Pdb_Jfn_Table+2] ; Dl = current stderr
|
|
mov cl,Io_Stderr ; Cl = original stderr
|
|
cmp dl,cl
|
|
je chk_x ; stderr matches
|
|
mov ah,CLOSE
|
|
int 21h ; close stderr
|
|
mov ds:Pdb_Jfn_Table+2,cl ; restore stderr
|
|
chk_x:
|
|
pop ds
|
|
ret
|
|
|
|
alloc_con:
|
|
SAVE <DX,SI,BP,BX,DS>
|
|
MOV DS,cs:[RESSEG]
|
|
ASSUME DS:RESGROUP
|
|
push cx
|
|
pop ax
|
|
mov bx, offset Pdb_Jfn_Table
|
|
add bx,ax
|
|
mov al,byte ptr ds:[bx]
|
|
push ax
|
|
push bx
|
|
mov byte ptr ds:[bx],0ffh
|
|
|
|
mov bx,word ptr ds:[RES_RDRINFO]
|
|
mov ax,word ptr ds:[RES_RDRINFO+2]
|
|
|
|
CMDSVC SVC_GETSTDHANDLE ; std hanlde in bx:cx
|
|
jc alloc_err
|
|
;; bx:cx = nt file handle
|
|
;; dx:ax = file size
|
|
push di
|
|
mov di, ax
|
|
xor si,si
|
|
xor bp,bp
|
|
mov al,0 ; free original console
|
|
mov ah,setdpb
|
|
int 21h
|
|
pop di
|
|
jc alloc_err
|
|
pop bx
|
|
pop ax
|
|
RESTORE <DS,BX,BP,SI,DX>
|
|
ret
|
|
|
|
alloc_err:
|
|
pop bx
|
|
pop ax
|
|
mov byte ptr ds:[bx],al
|
|
RESTORE <DS,BX,BP,SI,DX>
|
|
ret
|
|
|
|
|
|
; ds for tsr_loop is resseg on entry on exit transseg
|
|
|
|
ASSUME DS:RESGROUP
|
|
|
|
tsr_loop:
|
|
cmp byte ptr ds:[scs_cmdprompt],Prompt32
|
|
je tsr_ret
|
|
|
|
cmp byte ptr ds:[res_batstatus],0
|
|
je short tsr_nobat
|
|
cmp byte ptr ds:[scs_firsttsr],1
|
|
jne short tsr_retcode
|
|
jmp tsr_ret
|
|
|
|
tsr_nobat:
|
|
|
|
CMDSVC SVC_GETSTARTINFO ; return al = 1, if vdm has to
|
|
; terminate on app exit.
|
|
or al,al
|
|
jne tsr_ret
|
|
|
|
cmp byte ptr [scs_firsttsr],1
|
|
jne tsr_retcode
|
|
|
|
cmp word ptr ds:[RES_RDRINFO],0
|
|
je tsr_nordr
|
|
cmp word ptr ds:[RES_RDRINFO+2],0
|
|
jne tsr_ret
|
|
tsr_nordr:
|
|
mov byte ptr ds:[scs_firsttsr],0
|
|
mov al,Start16 ; parameter to put prompt
|
|
mov ah,FOR_TSR
|
|
call Do16BitPrompt ; ds is resseg here on return its transseg
|
|
or ah,ah
|
|
jnz tsr_exit
|
|
or al,al ; return al=0 to run 16bit binary al=1 getnextvdmcommand
|
|
jz tsr_dosonly
|
|
jmp tsr_ret
|
|
tsr_dosonly:
|
|
jmp GotCom ; go run through int21/exec
|
|
|
|
tsr_retcode:
|
|
mov al,return16 ; parameter to retun exit code if needed
|
|
mov ah,FOR_TSR
|
|
call Do16BitPrompt ; ds = resseg , on return its transseg
|
|
or ah,ah
|
|
jnz tsr_exit
|
|
or al,al ; return al=0 to run 16bit binary al=1 getnextvdmcommand
|
|
jnz tsr_ret
|
|
jmp GotCom
|
|
|
|
tsr_exit:
|
|
push cs
|
|
pop ds
|
|
assume ds:trangroup
|
|
mov [scs_tsrexit],1
|
|
tsr_ret:
|
|
jmp tsr_loop_ret
|
|
|
|
|
|
TRANCODE ENDS
|
|
END
|
|
|