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 xor si,si xor bp,bp mov al,2 mov ah,setdpb int 21h ; resets the TSR bit RESTORE xor ax,ax jmp short do_again cont_scs: SAVE xor si,si xor bp,bp mov al,2 mov ah,setdpb int 21h ; resets the TSR bit RESTORE 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 ; 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 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 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 ; 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 ; 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 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 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 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 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 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 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 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 ret alloc_err: pop bx pop ax mov byte ptr ds:[bx],al RESTORE 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