page ,132 title COMMAND - resident code for COMMAND.COM name COMMAND ;/* ; * Microsoft Confidential ; * Copyright (C) Microsoft Corporation 1991 ; * All Rights Reserved. ; */ ;***************************************************************************** ; ; MODULE: COMMAND.COM ; ; DESCRIPTIVE NAME: Default DOS command interpreter ; ; FUNCTION: This version of COMMAND is divided into three distinct ; parts. First is the resident portion, which includes ; handlers for interrupts 23H (Cntrl-C), 24H (fatal ; error), and 2EH (command line execute); it also has ; code to test and, if necessary, reload the transient ; portion. Following the resident is the init code, which ; is overwritten after use. Then comes the transient ; portion, which includes all command processing (whether ; internal or external). The transient portion loads at ; the end of physical memory, and it may be overlayed by ; programs that need as much memory as possible. When the ; resident portion of command regains control from a user ; program, a check sum is performed on the transient ; portion to see if it must be reloaded. Thus programs ; which do not need maximum memory will save the time ; required to reload COMMAND when they terminate. ; ; ENTRY POINT: PROGSTART ; ; INPUT: command line at offset 81H ; ; EXIT_NORMAL: No exit from root level command processor. Can exit ; from a secondary command processor via the EXIT ; internal command. ; ; EXIT_ERROR: Exit to prior command processor if possible, otherwise ; hang the system. ; ; INTERNAL REFERENCES: ; ; ROUTINES: See the COMMAND Subroutine Description Document ; (COMMAND.DOC) ; ; DATA AREAS: See the COMMAND Subroutine Description Document ; (COMMAND.DOC) ; ; EXTERNAL REFERENCES: ; ; ROUTINES: none ; ; DATA AREAS: none ; ;***************************************************************************** ; ; REVISION HISTORY ; ---------------- ; ; DOS 1.00 to DOS 3.30 ; -------------------------- ; SEE REVISION LOG IN COPY.ASM ALSO ; ; REV 1.17 ; 05/19/82 Fixed bug in BADEXE error (relocation error must return to ; resident since the EXELOAD may have overwritten the transient. ; ; REV 1.18 ; 05/21/82 IBM version always looks on drive A ; MSVER always looks on default drive ; ; REV 1.19 ; 06/03/82 Drive spec now entered in command line ; 06/07/82 Added VER command (print DOS version number) and VOL command ; (print volume label) ; ; REV 1.20 ; 06/09/82 Prints "directory" after directories ; 06/13/82 MKDIR, CHDIR, PWD, RMDIR added ; ; REV 1.50 ; Some code for new 2.0 DOS, sort of HACKey. Not enough time to ; do it right. ; ; REV 1.70 ; EXEC used to fork off new processes ; ; REV 1.80 ; C switch for single command execution ; ; REV 1.90 ; Batch uses XENIX ; ; Rev 2.00 ; Lots of neato stuff ; IBM 2.00 level ; ; Rev 2.01 ; 'D' switch for date time suppression ; ; Rev 2.02 ; Default userpath is NUL rather than BIN ; same as IBM ; COMMAND split into pieces ; ; Rev 2.10 ; INTERNATIONAL SUPPORT ; ; Rev 2.50 ; all the 2.x new stuff -MU ; ; Rev 3.30 (Ellen G) ; CALL internal command (TBATCH2.ASM) ; CHCP internal command (TCMD2B.ASM) ; INT 24H support of abort, retry, ignore, and fail prompt ; @ sign suppression of batch file line ; Replaceable environment value support in batch files ; INT 2FH calls for APPEND ; Lots of PTR fixes! ; ; Beyond 3.30 to forever (Ellen G) ; ---------------------- ; ; A000 DOS 4.00 - Use SYSPARSE for internal commands ; Use Message Retriever services ; /MSG switch for resident extended error msg ; Convert to new capitalization support ; Better error recovery on CHCP command ; Code page file tag support ; TRUENAME internal command ; Extended screen line support ; /P switch on DEL/ERASE command ; Improved file redirection error recovery ; (removed) Improved batch file performance ; Unconditional DBCS support ; Volume serial number support ; (removed) COMMENT=?? support ; ; A001 PTM P20 Move system_cpage from TDATA to TSPC ; ; A002 PTM P74 Fix PRESCAN so that redirection symbols do not ; require delimiters. ; ; A003 PTM P5,P9,P111 Included in A000 development ; ; A004 PTM P86 Fix IF command to turn off piping before ; executing ; ; A005 DCR D17 If user specifies an extension on the command ; line search for that extension only. ; ; A006 DCR D15 New message for MkDir - "Directory already ; exists" ; ; A007 DCR D2 Change CTTY so that a write is done before XDUP ; ; A008 PTM P182 Change COPY to set default if invalid function ; returned from code page call. ; ; A009 PTM P179 Add CRLF to invalid disk change message ; ; A010 DCR D43 Allow APPEND to do a far call to SYSPARSE in ; transient COMMAND. ; ; A011 DCR D130 Change redirection to overwrite an EOF mark ; before appending to a file. ; ; A012 PTM P189 Fix redirection error recovery. ; ; A013 PTM P330 Change date format ; ; A014 PTM P455 Fix echo parsing ; ; A015 PTM P517 Fix DIR problem with * vs *. ; ; A016 PTM P354 Fix extended error message addressing ; ; A017 PTM P448 Fix appending to 0 length files ; ; A018 PTM P566,P3903 Fix parse error messages to print out parameter ; the parser fails on. Fail on duplicate switches. ; ; A019 PTM P542 Fix device name to be printed correctly during ; critical error ; ; A020 DCR D43 Set append state off while in DIR ; ; A021 PTM P709 Fix CTTY printing ascii characters. ; ; A022 DCR D209 Enhanced error recovery ; ; A023 PTM P911 Fix ANSI.SYS IOCTL structure. ; ; A024 PTM P899 Fix EXTOPEN open modes. ; ; A025 PTM P922 Fix messages and optimize PARSE switches ; ; A026 DCR D191 Change redirection error recovery support. ; ; A027 PTM P991 Fix so that KAUTOBAT & AUTOEXEC are terminated ; with a carriage return. ; ; A028 PTM P1076 Print a blank line before printing invalid ; date and invalid time messages. ; ; A029 PTM P1084 Eliminate calls to parse_check_eol in DATE ; and TIME. ; ; A030 DCR D201 New extended attribute format. ; ; A031 PTM P1149 Fix DATE/TIME add blank before prompt. ; ; A032 PTM P931 Fix =ON, =OFF for BREAK, VERIFY, ECHO ; ; A033 PTM P1298 Fix problem with system crashes on ECHO >"" ; ; A034 PTM P1387 Fix COPY D:fname+,, to work ; ; A035 PTM P1407 Fix so that >> (appending) to a device does ; do a read to determine eof. ; ; A036 PTM P1406 Use 69h instead of 44h to get volume serial ; so that ASSIGN works correctly. ; ; A037 PTM P1335 Fix COMMAND /C with FOR ; ; A038 PTM P1635 Fix COPY so that it doesn't accept /V /V ; ; A039 DCR D284 Change invalid code page tag from -1 to 0. ; ; A040 PTM P1787 Fix redirection to cause error when no file is ; specified. ; ; A041 PTM P1705 Close redirected files after internal APPEND ; executes. ; ; A042 PTM P1276 Fix problem of APPEND paths changes in batch ; files causing loss of batch file. ; ; A043 PTM P2208 Make sure redirection is not set up twice for ; CALL'ed batch files. ; ; A044 PTM P2315 Set switch on PARSE so that 0ah is not used ; as an end of line character ; ; A045 PTM P2560 Make sure we don't lose parse, critical error, ; and extended message pointers when we EXIT if ; COMMAND /P is the top level process. ; ; A046 PTM P2690 Change COPY message "fn File not found" to ; "File not found - fn" ; ; A047 PTM P2819 Fix transient reload prompt message ; ; A048 PTM P2824 Fix COPY path to be upper cased. This was broken ; when DBCS code was added. ; ; A049 PTM P2891 Fix PATH so that it doesn't accept extra characters ; on line. ; ; A050 PTM P3030 Fix TYPE to work properly on files > 64K ; ; A051 PTM P3011 Fix DIR header to be compatible with prior releases. ; ; A052 PTM P3063,P3228 Fix COPY message for invalid filename on target. ; ; A053 PTM P2865 Fix DIR to work in 40 column mode. ; ; A054 PTM P3407 Code reduction and critical error on single line ; PTM P3672 (Change to single parser exported under P3407) ; ; A055 PTM P3282 Reset message service variables in INT 23h to fix ; problems with breaking out of INT 24h ; ; A056 PTM P3389 Fix problem of environment overlaying transient. ; ; A057 PTM P3384 Fix COMMAND /C so that it works if there is no space ; before the "string". EX: COMMAND /CDIR ; ; A058 PTM P3493 Fix DBCS so that CPARSE eats second character of ; DBCS switch. ; ; A059 PTM P3394 Change the TIME command to right align the display of ; the time. ; ; A060 PTM P3672 Code reduction - change PARSE and EXTENDED ERROR ; messages to be disk based. Only keep them if /MSG ; is used. ; ; A061 PTM P3928 Fix so that transient doesn't reload when breaking ; out of internal commands, due to substitution blocks ; not being reset. ; ; A062 PTM P4079 Fix segment override for fetching address of environment ; of parent copy of COMMAND when no COMSPEC exists in ; secondary copy of environment. Change default slash in ; default comspec string to backslash. ; ; A063 PTM P4140 REDIRECTOR and IFSFUNC changed interface for getting ; text for critical error messages. ; ; A064 PTM P4934 Multiplex number for ANSI.SYS changed due to conflict ; 5/20/88 with Microsoft product already shipped. ; ; A065 PTM P4935 Multiplex number for SHELL changed due to conflict ; 5/20/88 with Microsoft product already shipped. ; ; A066 PTM P4961 DIR /W /P scrolled first line off the screen in some ; 5/24/88 cases; where the listing would barely fit without the ; header and space remaining. ; ; A067 PTM P5011 For /E: values of 993 to 1024 the COMSPEC was getting ; 6/6/88 trashed. Turns out that the SETBLOCK for the new ; environment was putting a "Z block" marker in the old ; environment. The fix is to move to the old environment ; to the new environment before doing the SETBLOCK. ; ; A068 PTM P5568 IR79754 APPEND /x:on not working properly with DIR/VOL ; 09/19/88 because the check for APPEND needed to be performed ; before the DIR's findfirst. ; ; A069 PTM P5726 IR80540 COMSPEC_flag not properly initialized and ; 10/30/88 executed. Causing AUSTIN problem testing LAN/DW4 re- ; loading trans w/new comspec with no user change comspec. ; ; A070 PTM P5734 IR80484 Batch file causes sys workspace to be corrupted. ; 11/05/88 Expansion of environment variables into batch line of ; 128 chars was not being counted and "%" which should be ; ignored were being counted. ; ; A071 PTM P5854 IR82061 Invalid COMMAND.COM when Word Perfect, Prompt ; 03/02/89 used. Comspec_flag was not in protected data file be- ; ing included in checksum and was being overwritten by ; WP. Moved var from Tspc to Tdata so Trans would reload. ; Also removed fix A069 (because flag now protected). ; ; C001 VERSION 4.1 Add new internal command - SERVICE - to display the DOS ; 07/25/89 version and CSD version in U.S. date format. Files ; changed - TRANMSG,.SKL,COMMAND1,TDATA,TCMD2A,USA.MSG ; ;*********************************************************************************** ; ; Revision History ; ================ ; ; M021 SR 08/23/90 Fixed Ctrl-C handler to handle Ctrl-C ; at init time (date/time prompt) ; .xcref .xlist include dossym.inc ; basic DOS symbol set include syscall.inc ; DOS function names include comsw.asm ; build version info include comequ.asm ; common command.com symbols include resmsg.equ ; resident message names include comseg.asm ;segment ordering .list .cref CODERES segment public byte CODERES ends DATARES segment public byte extrn AccDen:byte extrn Batch:word extrn EchoFlag:byte extrn ExeBad:byte extrn ExecEMes:byte extrn ExecErrSubst:byte extrn ExtCom:byte extrn ForFlag:byte extrn IfFlag:byte extrn InitFlag:BYTE extrn Nest:word extrn PipeFlag:byte extrn RBadNam:byte extrn RetCode:word extrn SingleCom:word extrn TooBig:byte extrn OldDS:word EXTRN SCS_REENTERED:BYTE EXTRN SCS_CMDPROMPT:BYTE DATARES ends INIT segment public para extrn ConProc:near extrn Init_Contc_SpecialCase:near INIT ends include envdata.asm Prompt32 equ 1 ;*** START OF RESIDENT PORTION CODERES segment public byte public Ext_Exec public ContC public Exec_Wait public Exec_Ret assume cs:CODERES,ds:NOTHING,es:NOTHING,ss:NOTHING extrn LodCom:near extrn LodCom1:near org 0 Zero = $ ;; org 80h - 1 ;;ResCom label byte ;; public ResCom ;; org 100h public StartCode StartCode: ;; jmp RESGROUP:ConProc ;*** EXEC error handling ; ; COMMAND has issued an EXEC system call and it has returned an error. ; We examine the error code and select an appropriate message. ; Bugbug: optimize reg usage in following code? Careful of DX! ; Condense the error scan? ; RBADNAM is checked by transient, no need here? ; Move below Ext_Exec. Exec_Err: ;SR; ; ds,es are setup when the transient jumps to Ext_Exec. So segment regs are ;in order here assume ds:DATARES,es:DATARES ; Bugbug: can we use byte compares here? ; Might be able to use byte msg#s, too. ; Store errors in a 3 or 4 byte table. Msg #s in another. ; Speed not high priority here. ; Move this to transient. mov bx,offset DATARES:RBadNam cmp al,ERROR_FILE_NOT_FOUND je GotExecEMes ; bad command mov bx,offset DATARES:TooBig cmp al,ERROR_NOT_ENOUGH_MEMORY je GotExecEMes ; file not found mov bx,offset DATARES:ExeBad cmp al,ERROR_BAD_FORMAT je GotExecEMes ; bad exe file mov bx,offset DATARES:AccDen cmp al,ERROR_ACCESS_DENIED je GotExecEMes ; access denied Default_Message: mov bx,offset DATARES:ExecEMes ; default message mov si,offset DATARES:ExecErrSubst ; get address of subst block GotExecEMes: mov dx,bx ; DX = ptr to msg ;; williamh: no reason of doing this. When command.com receives a command, ;; it means the VDM process has been created successfully and there ;; is no way for the parent process to know that we are not able ;; to launch the program and therefore, it won't display any error ;; message for us. ;; cmp byte ptr [scs_reentered],1 ;; jne NoErrMsg ;; cmp byte ptr [scs_cmdprompt],Prompt32 ;; je NoErrMsg invoke RPrint NoErrMsg: jmp short NoExec ;*** EXEC call ; ; The transient has set up everything for an EXEC system call. ; For cleanliness, we issue the EXEC here in the resident ; so that we may be able to recover cleanly upon success. ; ; CS,DS,ES,SS = DATARES seg addr Ext_Exec: ;SR; ; The words put on the stack by the stub will be popped off when we finally ;jump to LodCom ( by LodCom). ; ;; int 21h ; do the exec Exec_Ret: jc Exec_Err ; exec failed ; The exec has completed. Retrieve the exit code. Exec_Wait: mov ah,WAITPROCESS ; get errorlevel int 21h ; get the return code mov RetCode,ax ; See if we can reload the transient. The external command ; may have overwritten part of the transient. NoExec: ;SR; ; ds = es = ss = DATARES when we jump to LodCom ; jmp LodCom ;*** Int 23 (ctrl-c) handler ; ; This is the default system INT 23 handler. All processes ; (including COMMAND) get it by default. There are some ; games that are played: We ignore ^C during most of the ; INIT code. This is because we may perform an ALLOC and ; diddle the header! Also, if we are prompting for date/time ; in the init code, we are to treat ^C as empty responses. ; Bugbug: put init ctrl-c handling in init module. ;SR; ; The stub has pushed the previous ds and DATARES onto the stack. We get ;both these values off the stack now ; ContC proc far assume cs:CODERES,ds:NOTHING,es:NOTHING,ss:NOTHING pop ds ;ds = DATARES assume ds:DATARES ; pop OldDS ;OldDS = old ds test InitFlag,INITINIT ; in initialization? jz NotAtInit ; no test InitFlag,INITSPECIAL ; doing special stuff? jz CmdIRet ; no, ignore ^C pop ds ; restore before jumping; M021 jmp RESGROUP:Init_ContC_SpecialCase ; Yes, go handle it CmdIret: ;SR; ; Restore ds to its previous value ; ; mov ds,OLdDS ; pop ds iret ; yes, ignore the ^C NotAtInit: test InitFlag,INITCTRLC ; are we already in a ^C? jz NotInit ; nope too. ;* We are interrupting ourselves in this ^C handler. We need ; to set carry and return to the user sans flags only if the ; system call was a 1-12 one. Otherwise, we ignore the ^C. cmp ah,1 jb CmdIRet cmp ah,12 ja CmdIRet pop ds ;restore ds to old value add sp,6 ; remove int frame stc ; mov ds,OldDS ;restore ds to its old value ret 2 ; remove those flags... NotInit: ;* We have now received a ^C for some process (maybe ourselves ; but not at INIT). ; ; Note that we are running on the user's stack!!! Bad news if ; any of the system calls below go and issue another INT ; 24... Massive stack overflow! Another bad point is that ; SavHand will save an already saved handle, thus losing a ; possible redirection... ; ; All we need to do is set the flag to indicate nested ^C. ; The above code will correctly flag the ^C diring the ; message output and prompting while ignoring the ^C the rest ; of the time. ; ; Clean up: flush disk. If we are in the middle of a batch ; file, we ask if he wants to terminate it. If he does, then ; we turn off all internal flags and let the DOS abort. or InitFlag,INITCTRLC ; nested ^c is on sti ;; push cs ; el yucko! change the user's ds!! ;; pop ds ;; assume ds:RESGROUP pop ax ;discard the old ds value mov ax,SingleCom or ax,ax jnz NoReset push ax mov ah,DISK_RESET int 21h ; reset disks in case files were open pop ax NoReset: ; In the generalized version of FOR, PIPE and BATCH, we would ; walk the entire active list and free each segment. Here, ; we just free the single batch segment. test Batch,-1 jz ContCTerm or ax,ax jnz ContCTerm invoke SavHand invoke AskEnd ; ask if user wants to end batch ; If the carry flag is clear, we do NOT free up the batch file jnc ContBatch mov cl,EchoFlag ; get current echo flag push bx ClearBatch: mov es,Batch ; get batch segment mov di,BatFile ; get offset of batch file name ; Bugbug: verify the following shell interface still works ;; mov ax,MULT_SHELL_BRK ; does the SHELL want this terminated? ;; int 2Fh ; call the SHELL ;; cmp al,SHELL_ACTION ; does shell want this batch? ;; je Shell_Bat_Cont ; yes - keep it mov bx,es:BatForPtr ; get old FOR segment cmp bx,0 ; is a FOR in progress je no_bat_for ; no - don't deallocate push es ; mov es,bx ; yes - free it up... mov ah,DEALLOC ; int 21h ; pop es ; restore to batch segment No_Bat_For: mov cl,es:BatEchoFlag ; get old echo flag mov bx,es:BatLast ; get old batch segment mov ah,DEALLOC ; free it up... int 21h mov Batch,bx ; get ready to deallocate next batch dec nest ; is there another batch file? jnz ClearBatch ; keep going until no batch file ; We are terminating a batch file; restore the echo status Shell_Bat_Cont: ; continue batch for SHELL pop bx mov EchoFlag,cl ; reset echo status mov PipeFlag,0 ; turn off pipeflag ContBatch: invoke Crlf ; print out crlf before returning invoke RestHand ; Yes, we are terminating. Turn off flags and allow the DOS to abort. ContCTerm: xor ax,ax ; indicate no read mov bp,ax ; The following resetting of the state flags is good for the ; generalized batch processing. mov IfFlag,al ; turn off iffing mov ForFlag,al ; turn off for processing call ResPipeOff cmp SingleCom,ax ; see if we need to set singlecom jz NoSetSing mov SingleCom,-1 ; cause termination on ; pipe, batch, for NoSetSing: ; If we are doing an internal command, go through the reload process. ; If we are doing an external, let DOS abort the process. ; In both cases, we are now done with the ^C processing. and InitFlag,not INITCTRLC cmp ExtCom,al jnz DoDAb ; internal ^c jmp LodCom1 DoDAb: stc ; tell dos to abort ;SR; ;We dont need to restore ds here because we are forcing DOS to do an abort ;by setting carry and leaving flags on the stack ; ret ; Leave flags on stack ContC endp ;SR; ; ds = DATARES on entry. This routine is called from DskErr and LodCom1 and ;both have ds = DATARES ; ResPipeOff: public ResPipeOff assume ds:DATARES,es:NOTHING savereg xor ax,ax xchg PipeFlag,al or al,al jz NoPipePop shr EchoFlag,1 NoPipePop: restorereg return CODERES ends end