        page ,132
        title   COMMAND Resident DATA
;
;                        IBM Corporation
;                        Copyright (C) IBM Corporation 1991-1993
;                        All Rights Reserved.
;

;
;       Revision History
;       ================
;       M003    SR      07/16/90        Added LoadHiFlg for LoadHigh support
;
;       M004    SR      07/17/90        Transient is now moved to its final
;                               location at EndInit time by allocating
;                               the largest available block, moving
;                               the transient to the top of the block
;                               and then freeing up the block.
;
;       M027    SR      9/20/90 Fixed bug #2827. EndInit was using
;                               INIT seg variables after INIT seg
;                               had been freed.
;
;       M036    SR      11/1/90 Free up environment segment passed
;                               by Exec always.
;
;       t-richj         5-20-92 Removed LoadHiFlg

.xlist
.xcref
        include dossym.inc
        include pdb.inc
        include syscall.inc
        include comsw.asm
        include comseg.asm
        include resmsg.equ
        include comequ.asm
.list
.cref

;       Equates for initialization (from COMEQU)
;
;       Bugbug:  Toss these after putting ctrl-c handler in init module.

INITINIT    equ     01h                 ; initialization in progress
INITSPECIAL equ     02h                 ; in initialization time/date routine
INITCTRLC   equ     04h                 ; already in ^C handler


CODERES segment public byte
        extrn   Ext_Exec:near
        extrn   MsgRetriever:far
        extrn   TRemCheck:near
CODERES ends

INIT    segment

        extrn   ConProc:near
        extrn   AllocedEnv:byte
        extrn   UsedEnv:word
        extrn   OldEnv:word
        extrn   EnvSiz:word
        extrn   TrnSize:word            ; M004

INIT    ends

TAIL    segment

        extrn   TranStart       :word

TAIL    ends

TRANCODE        segment public byte
        extrn   Command:near
TRANCODE        ends

TRANSPACE       segment

        extrn   TranSpaceEnd    :byte

TRANSPACE       ends

;SR;
; All the routines below are entry points into the stub from the transient.
;The stub will then transfer control to the appropriate routines in the
;resident code segment, wherever it is present.
;

DATARES segment

        extrn   Exec_Trap       :near
        extrn   RemCheck_Trap   :near
        extrn   MsgRetrv_Trap   :near
        extrn   HeadFix_Trap    :near
        extrn   Issue_Exec_Call :near

DATARES ends


DATARES segment public byte
        assume  cs:DATARES
        Org     0
ZERO    =       $

        public  Abort_Char
        public  Append_Flag
        public  Append_State
        public  BadFatSubst
        public  command_origin
        public  Batch
        public  Batch_Abort
        public  BlkDevErrRw
        public  BlkDevErrSubst
        public  Call_Batch_Flag
        public  Call_Flag
        public  CDevAt
        public  CharDevErrSubst
        public  CharDevErrRw
        public  Com_Fcb1
        public  Com_Fcb2
        public  Com_Ptr
        public  ComDrv
        public  ComSpec
        public  ComSpec_End
        public  Crit_Err_Info
; VCB - Delete unused variables
;       public  Crit_Msg_Off
;       public  Crit_Msg_Seg
        public  CritMsgPtrs
        public  DataResEnd
        public  Dbcs_Vector_Addr
        public  DevName
        public  DrvLet
        public  EchoFlag
        public  EnvirSeg
        public  ErrCd_24
        public  ErrType
        public  Exec_block
        public  ExecErrSubst
        public  Extcom
        public  ExtMsgEnd
        public  Fail_Char
        public  fFail
        public  ForFlag
        public  ForPtr
        public  FUCase_Addr
        public  Handle01

; VCB - Add support for /H switch
        public  high_flag

        public  IfFlag
        public  Ignore_Char
        public  In_Batch
        public  InitFlag
        public  InPipePtr
        public  Int_2e_Ret
        public  Int2fHandler
        public  Io_Save
        public  LenMsgOrPathBuf
        public  Loading
        public  LTpa
        public  MemSiz
        public  MsgBuffer
        public  MsgPtrLists
        public  MySeg
        public  MySeg1
        public  MySeg2
        public  MySeg3
        public  NeedVol
        public  NeedVolSubst
        public  Nest
        public  Next_Batch
        public  No_Char
        public  NullFlag
        public  NUMEXTMSGS
        public  NUMPARSMSGS
        public  OldErrNo
        public  OldTerm
        public  OutPipePtr
        public  Parent
        public  ParsMsgPtrs
        public  PermCom
        public  SemiPermCom
        public  Pipe1
        public  Pipe2
        public  PipeFiles
        public  PipeFlag
        public  PipePtr
        public  PipeStr
        public  PutBackComSpec
        public  PutBackDrv
        public  PutBackSubst
        public  RDirChar
; VCB - Move these to the transient portion of COMMAND.COM (TSPC.ASM)
;       public  Re_Out_App
;       public  Re_OutStr
        public  ResMsgEnd
        public  CmdFlags
        public  Res_Tpa
        public  RestDir
; VCB - Delete unused variable
;       public  ResTest
        public  RetCode
        public  Retry_Char
        public  RSwitChar
        public  SafePathBuffer          ; MSKK01 07/14/89
        public  Save_Pdb
        public  SingleCom
        public  Sum
        public  Suppress
        public  Trans
        public  TranVarEnd
        public  TranVars
        public  TrnSeg
        public  TrnMvFlg
        public  VerVal
        public  VolName
        public  VolSer
        public  Yes_Char

        public  ResSize
        public  RStack
        public  OldDS

;       public  LoadHiFlg               ;For LoadHigh support ; M003

        extrn   LodCom_Trap:near
        extrn   Alloc_error:near

;       The command_origin flag must be found externally by the XCOPY and
;       MOVE commands, which alter their behavior based on whether or
;       not the current command was directly entered from the keyboard.
;
;       It is accessed directly by scanning for the string 'cox' in the
;       parent's PSP segment (only if the Parent's PSP points to itself).
;       The reason it is not practical to make it available through an Int2f
;       is that only our INITIAL loaded copy has an Int2f, not the necessarily
;       the one that spawned the XCOPY or MOVE command.

                public  command_copy_id
command_copy_id db      'cox'                   ; stamp
command_origin  dw      0

ifdef ROMDOS

        include command.loc

ifdef COMMAND_LO

;       COMMAND image is in extended address space.

;       Global Descriptor Table (GDT) for use with int 15h block move

Int15GDT        db      10h dup (0)             ; reserved zero
gdtSrcLen       dw      COMMAND_SIZ             ; src segment length
gdtSrcLo        dw      COMMAND_LO              ; low 16 bits of src address
gdtSrcHi        db      COMMAND_HI              ; high 8 bits of src address
                db      93h                     ; access rights byte
                db      2 dup (0)               ; reserved zero
gdtDstLen       dw      COMMAND_SIZ             ; dst segment length
gdtDstLo        dw      ?                       ; low 16 bits of dst address
gdtDstHi        db      ?                       ; high 8 bits of dst address
                db      93h                     ; access rights byte
                db      12h dup (0)             ; reserved zero

        public  Int15GDT,gdtSrcLen,gdtSrcLo,gdtSrcHi
        public  gdtDstLen,gdtDstLo,gdtDstHi

endif
endif ; ROMDOS



;***    Message substitution blocks


BlkDevErrSubst  label   byte
BlkDevErrRw     subst   <STRING,>               ; "reading" or "writing"
BadFatSubst     label   byte
                subst   <CHAR,DATARES:DrvLet>   ; block device drive letter

DrvLet          db      'A'                     ; drive letter


CharDevErrSubst label   byte
CharDevErrRw    subst   <STRING,>                 ; "reading" or "writing"
CharDevErrDev   subst   <STRING,DATARES:DevName> ; character device name

; VCB - Use VolName buffer for this
;DevName         db      8 dup (?),0               ; device name, asciiz


NeedVolSubst    label   byte
                subst   <STRING,DATARES:VolName>        ; volume name
                subst   <HEX,DATARES:VolSer+2>          ; hi word of serial #
                subst   <HEX,DATARES:VolSer>            ; lo word of serial #

;               NOTE:   VolName and VolSer must be adjacent
VolName         db      11 dup (?),0            ; volume name
VolSer          dd      0                       ; volume serial #

; VCB - Use VolName buffer for this
DevName         equ     VolName+3

CDevAt          db      ?

; VCB - Define this with common definition above
;BadFatSubst     label   byte
;                subst   <CHAR,DATARES:DrvLet>   ; drive letter


PutBackSubst    label   byte
PutBackComSpec  subst   <STRING,>                       ; comspec string
                subst   <CHAR,DATARES:PutBackDrv>       ; drive to put it in

PutBackDrv      db      ' '                     ; drive letter


ExecErrSubst    subst   <STRING,DATARES:SafePathBuffer>


NeedVol         dd      ?       ; ptr to volume name from get ext err
ErrType         db      ?       ; critical error message style, 0=old, 1=new

Int_2e_Ret      dd      ?       ; magic command executer return address
Save_Pdb        dw      ?
Parent          dw      ?
OldTerm         dd      ?
ErrCd_24        dw      ?
Handle01        dw      ?
Loading         db      0
Batch           dw      0       ; assume no batch mode initially

;               Bugbug: ComSpec should be 64+3+12+1?
;               What's this comspec_end about?
ComSpec         db      64 dup (0)
ComSpec_End     dw      ?

Trans           label   dword
                dw      TRANGROUP:Command
TrnSeg          dw      ?

TrnMvFlg        db      0       ; set if transient portion has been moved

In_Batch        db      0       ; set if we are in batch processing mode
Batch_Abort     db      0       ; set if user wants to abort from batch mode

ComDrv          db      ?       ; drive spec to load autoexec and command
MemSiz          dw      ?
Sum             dw      ?
ExtCom          db      1       ; for init, pretend just did an external
RetCode         dw      ?
Crit_Err_Info   db      ?       ; hold critical error flags for r,i,f


; The echo flag needs to be pushed and popped around pipes and batch files.
; We implement this as a bit queue that is shr/shl for push and pop.

EchoFlag        db      00000001b       ; low bit true => echo commands
Suppress        db      1               ; used for echo, 1=echo line
Io_Save         dw      ?
RestDir         db      0
PermCom         db      0               ; true => permanent command
SemiPermCom     dw      -1              ; true => semi-permanent command (/K)
SingleCom       dw      0               ; true => single command version
VerVal          dw      -1
fFail           db      0               ; true => fail all int 24s
IfFlag          db      0               ; true => IF statement in progress

ForFlag         db      0               ; true => FOR statement in progress
ForPtr          dw      0

Nest            dw      0               ; nested batch file counter
Call_Flag       db      0               ; no CALL (batch command) in progress
Call_Batch_Flag db      0
Next_Batch      dw      0               ; address of next batch segment
NullFlag        db      0               ; flag if no command on command line
FUCase_Addr     db      5 dup (0)       ; buffer for file ucase address
; Bugbug: don't need crit_msg_ anymore?
; VCB - Delete unused variables
;Crit_Msg_Off    dw      0               ; saved critical error message offset
;Crit_Msg_Seg    dw      0               ; saved critical error message segment
Dbcs_Vector_Addr dw     0               ; DBCS vector offset
                 dw     0               ; DBCS vector segment

Append_State    dw      0               ; current state of append
                                        ;  (if Append_Flag is set)
Append_Flag     db      0               ; set if append state is valid

; VCB - Move these to the transient portion of COMMAND.COM (TSPC.ASM)
;Re_Out_App      db      0
;Re_OutStr       db      64+3+13 dup (?)


; We flag the state of COMMAND in order to correctly handle the ^Cs at
; various times.  Here is the breakdown:
;
;   INITINIT    We are in the init code.
;   INITSPECIAL We are in the date/time prompt
;   INITCTRLC   We are handling a ^C already.
;
; If we get a ^C in the initialization but not in the date/time prompt, we
; ignore the ^C.  This is so the system calls work on nested commands.
;
; If we are in the date/time prompt at initialization, we stuff the user's
; input buffer with a CR to pretend an empty response.
;
; If we are already handling a ^C, we set the carry bit and return to the user
; (ourselves).  We can then detect the carry set and properly retry the
; operation.

InitFlag        db      INITINIT

; Note:  these two bytes are referenced as a word
PipeFlag        db      0
PipeFiles       db      0

;--- 2.x data for piping
;
; All the "_" are substituted later, the one before the : is substituted
; by the current drive, and the others by the CreateTemp call with the
; unique file name. Note that the first 0 is the first char of the pipe
; name. -MU
;
;--- Order-dependent, do not change

;;;Pipe1                db      "_:/"
;;;Pipe1T               db      0
;;;             db      "_______.___",0
;;;Pipe2                db      "_:/"
;;;Pipe2T               db      0
;;;             db      "_______.___",0

;SR
; Pipe1 & Pipe2 now need to store full-fledged pathnames
;

; Bugbug:  can we find any way around maintaining these
; large buffers?

Pipe1           db      67+12 dup (?)
Pipe2           db      67+12 dup (?)

PipePtr         dw      ?

PipeStr         db      129 dup (?)

EndPipe label   byte                    ; marks end of buffers; M004

;SR;
; We can move our EndInit code into above buffers. This way, the code will
;automatically be discarded after init.
;
; M004; We overlap our code with the Pipe buffers located above by changing
; M004; the origin.
;
        ORG     Pipe1                   ; M004

; Bugbug:  really need a procedure header for EndInit, describing
; what it expects, what it does.

Public  EndInit
EndInit:
        push    ds
        push    es                      ;save segments
; VCB - DS is set to data area segment in INIT.ASM, CS may be in UMB
;       push    cs
;       pop     ds
        assume  ds:RESGROUP

;
; M004; Save size of transient here before INIT segment is deallocated
;
        mov     dx,TrnSize              ; M004
;M027
; These variables are also defined in the INIT segment and need to be saved
;before we resize
;
        mov     ax,OldEnv               ; Old Environment seg ;M027
        mov     bx,EnvSiz               ; Size of new environment ;M027
        mov     cx,UsedEnv              ; Size of old environment ;M027
        push    ax                      ; Save all these values ;M027
        push    bx                      ; M027
        push    cx                      ; M027


; Bugbug:  push ds, pop es here.
;       mov     bx,ds
;       mov     es,bx                   ;es = RESGROUP
        push    ds
        pop     es
;
;ResSize is the actual size to be retained -- only data for HIMEM COMMAND,
; code + data for low COMMAND

; VCB - Deallocate original block if COMMAND.COM was loaded high and
;       reset allocation strategy.

        mov     bx,ResSize              ;Total size of resident
        mov     ah,4ah                  ;Reallocate memory function
        cmp     high_flag,2             ;Loaded high ?
        jne     setmem                  ;No
        xor     bx,bx                   ;First fit strategy
        mov     ax,5801h                ;Set allocation strategy function
        int     21h                     ;Call DOS
; VCB - Release original environment segment (if any)
        mov     cx,ds:[7eh]             ;Get original environment segment
        jcxz    @f                      ;Skip if 0
        push    es                      ;Save ES
        mov     es,cx                   ;Set ES
        mov     ah,49h                  ;Release memory function
        int     21h                     ;Call DOS
        pop     es                      ;Restore ES
@@:     mov     ah,49h                  ;Release memory function
setmem: int     21h                     ;Set block to resident size
; end /H
;
;We check if this is for autoexec.bat (PermCom = 1). If so, we then
;allocate a new batch segment, copy the old one into new batchseg and free
;the old batchseg. Remember that the old batchseg was allocated on top of the
;transient and we will leave a big hole if TSRs are loaded by autoexec.bat
;
; Bugbug:  also describe why we alloc & copy batch seg BEFORE environment.
        cmp     PermCom,1               ;permanent command.com?
        jne     adjust_env              ;no, do not free batchseg

        cmp     Batch,0                 ;was there a valid batchseg?
        je      adjust_env              ;no, dont juggle

        mov     bx,((SIZE BatchSegment) + 15 + 1 + 0fh)/16 ;batchseg size
        mov     ah,ALLOC
        int     21h
; Bugbug:  I just had a thought.  If DOS or SHARE or somebody leaves
; a hole, the batch segment COULD already be in the ideal place.  We
; could be making it worse!  We're second-guessing where memory
; allocations go, which might not be such a great idea.  Is there
; a strategy, short of doing something even worse like diddling
; arena headers, where we can minimize the possibility of fragmentation
; under all cases?  Hmm..
        jc      adjust_env              ;no memory, use old batchseg
        mov     es,ax                   ;es = New batch segment
        xor     di,di
        xor     si,si

        push    ds
        mov     ds,Batch                ;ds = Old Batch Segment
        assume  ds:nothing
        mov     cx,SIZE BatchSegment
        add     cx,16                   ;for the filename
        ; Bugbug: 16?  Shouldn't this be a common equate or something?
        ; It's sure be bad if we copied more bytes than the batch segment
        ; holds!
        cld
        rep     movsb
        pop     ds
        assume  ds:RESGROUP

        mov     cx,es                   ;save new batch segment
        mov     es,Batch
        mov     ah,DEALLOC
        int     21h                     ;free the old batch segment
        ; Bugbug:  should we check for error?

        mov     cs:Batch,cx             ;store new batch segment address

adjust_env:

; VCB - Set high first allocation strategy to allow master environment
;       to be loaded high, this will only have an effect if /H was
;       specified and the UMB chain was successfully linked in
;       (This is done in INIT.ASM)

        mov     bx,80h                  ;First fit, high first strategy
        mov     ax,5801h                ;Set allocation strategy function
        int     21h                     ;Call DOS
; end /H

        pop     cx                      ;cx = size of old env ;M027
        pop     bx                      ;bx = size of new env needed ;M027
        pop     bp                      ;bp = old env seg ;M027
;
;Allocate the correct size for the environment
;

        mov     ah,ALLOC
        int     21h                     ;get memory
        jc      nomem_err               ;out of memory,signal error
        ; Bugbug:  why not continue, leaving environment where it is?

        mov     cs:EnvirSeg,ax          ;Store new environment segment
        mov     cs:PDB_Environ,ax               ;Put new env seg in PSP
        mov     es,ax                   ;es = address of allocated memory
        assume  es:nothing

;
;Copy the environment to the newly allocated segment
;
        push    ds
        mov     ds,bp                   ;ds = Old environment segment
        assume  ds:nothing

        xor     si,si
        mov     di,si                   ;Start transfer from 0

        cld
        rep     movsb                   ;Do the copy

        pop     ds                      ;ds = RESGROUP
        assume  ds:RESGROUP
;
; We have to free the old environment block if it was allocated by INIT
;
; Bugbug:  is this only for the case when we were NOT passed an environment,
; or does it also apply to passed environments?
;M036
; Free up old env segment always because this is a copy passed by Exec and
; takes up memory that is never used
;
;M044
; Go back to the old strategy of not freeing the environment. Freeing it leaves
; a hole behind that Ventura does not like. Basically, Ventura gives strange
; errors if it gets a memory alloc that it is below its load segment. The
; freed environment creates a large enough hole for some of its allocs to fit
; in
;
        cmp     AllocedEnv,0            ;has env been allocated by INIT?
        je      no_free                 ;no, do not free it

        mov     es,bp
        mov     ah,DEALLOC
        int     21h                     ;Free it
no_free:

; VCB - Reset allocation strategy and UMB link state in case they
;       were set for /H

        xor     bx,bx                   ;First fit strategy
        mov     ax,5801h                ;Set allocation strategy function
        int     21h                     ;Call DOS
        xor     bx,bx                   ;Unlink UMBs
        mov     ax,5803h                ;Set UMB link state function
        int     21h                     ;Call DOS
; end /H

;
; M004; Start of changes
;

;
; Move the transient now. We will allocate the biggest block available
; now and move the transient to the top of the block. We will then
; deallocate this block. When the resident starts executing, it will
; hopefully allocate this block again and find the transient intact.
;
        MOV     cs:TrnMvFlg, 1                  ; Indicate that transient has been moved
        push    es
        mov     si,offset ResGroup:TranStart
        xor     di,di
        mov     cx,offset TranGroup:TranSpaceEnd ;size to move
;
; Find the largest block available
;
        mov     bx,0ffffh
        mov     ah,ALLOC
        int     21h

;
; dx = size of transient saved previously
;
        cmp     bx,dx                   ;enough memory?
        jb      nomem_err               ;not enough memory for transient

        mov     ah,ALLOC
        int     21h                     ;get the largest block
        jc      nomem_err               ;something is really screwed up

        push    ax                      ;save memory address
        add     ax,bx                   ;ax = top of my memory block
        sub     ax,dx                   ;less size of transient
        mov     cs:TrnSeg,ax            ;save transient segment
        mov     es,ax                   ;
        pop     ax                      ;restore our seg addr

;
; Everything is set for a move. We need to move in the reverse direction to
; make sure we dont overwrite ourselves while copying
;
        add     si,cx
        dec     si
        add     di,cx
        dec     di
        std
        rep     movsb
        cld
;
; Now we have to free up this block so that resident can get hold of it
;
        mov     es,ax
        mov     ah,DEALLOC
        int     21h                     ;release the memory block

;
; M004; End of changes
;

        mov     cs:InitFlag,FALSE       ;indicate INIT is done

        pop     es
        pop     ds
        ; Bugbug:  did we need to save & restore seg reg's during EndInit?
        assume  ds:nothing

        jmp     LodCom_Trap             ;allocate transient

nomem_err:
;
;We call the error routine which will never return. It will either exit
;with an error ( if not the first COMMAND ) or just hang after an error
;message ( if first COMMAND )
;

        jmp     Alloc_error

; VCB - Add support for /H switch
high_flag       db      0

public EndCodeInit                      ; M004
EndCodeInit     label   byte            ; M004

;
; M004; Check if the EndInit code will fit into the Pipe buffers above.
; M004; If not, we signal an assembly error
;
IF2
        IF ($ GT EndPipe)
                .err
                %out    "ENDINIT CODE TOO BIG"
        ENDIF
ENDIF
;
; M004; Set the origin back to what it was at the end of the buffers
;
                ORG     EndPipe         ; M004



InPipePtr       dw      offset DATARES:Pipe1
OutPipePtr      dw      offset DATARES:Pipe2

Exec_Block      label   byte            ; the data block for exec calls
EnvirSeg        dw      ?
Com_Ptr         label   dword
                dw      80h             ; point at unformatted parameters
                dw      ?
Com_Fcb1        label   dword
                dw      5Ch
                dw      ?
Com_Fcb2        label   dword
                dw      6Ch
                dw      ?

;               variables passed to transient
TranVars        label   byte
                dw      offset DATARES:HeadFix_Trap
MySeg           dw      0               ; put our own segment here
LTpa            dw      0               ; will store tpa segment here

RSwitChar       db      "/"
RDirChar        db      "\"
                dw      offset DATARES:Issue_Exec_Call
MySeg1          dw      ?
                dw      offset DATARES:RemCheck_Trap
MySeg2          dw      0
; VCB - Delete unused variable
;ResTest         dw      0
Res_Tpa         dw      0               ; original tpa (not rounded to 64k)
CmdFlags        dw      0               ; flags word (see CMDFLAGS_*)
TranVarEnd      label   byte

OldErrNo        dw      ?


;*              NOTE:  MsgBuffer and SafePathBuffer use the same
;               memory.  MsgBuffer is only used while a command
;               is being executed.  SafePathBuffer is no longer
;               needed, since it is used for unsuccessful program
;               launches.

MsgBuffer       label   byte            ; buffer for messages from disk
SafePathBuffer  label   byte            ; resident pathname for EXEC
;               Bugbug: Why so big a buffer?
                db      64+3+13 dup (0) ; path + 'd:\' 'file.ext' + null
LenMsgOrPathBuf equ     $ - MsgBuffer


Int2fHandler    dd      ?       ; address of next int 2f handler
ResMsgEnd       dw      0       ; holds offset of msg end (end of resident)

;SR;
; The three vars below have been added for a pure COMMAND.COM
;

ResSize         dw      ?

;SR;
; Moved the stack here from the code segment
;
        db      (80h - 8) dup (?)
RStack  label   word

OldDS           dw      ?       ;keeps old ds value when jumping to
                                ;resident code segments

;LoadHiFlg      db      0       ;Flag set to 1 if UMB loading enabled ; M003

;
; -----------------------------------------------------------------------------
;
; VCB - Decrease resident size of COMMAND.COM by using common data area
HV_RDATA = 1
include highvar.inc             ;Add variables for 6.0 loadhigh functionality
;
; -----------------------------------------------------------------------------
;

;***    MESSAGES
;       and other translatable text

        include comrmsg.inc     ;M00

DATARES ends
        end
