        page ,132
        title   COMMAND2 - resident code for COMMAND.COM part II
        name    COMMAND2

__TONYI__ = 1           ; Fake int for CLOSE and SetVect

;/*
;                        IBM Corporation
;                        Copyright (C) IBM Corporation 1991-1993
; *                      All Rights Reserved.
; */
;
;       Revision History
;       ================
;
; M038  SR  11/5/90     Changed stuff for Novell RPL. These guys cannot
;                       reserve memory by changing int 12h and then give it
;                       back to DOS by changing arenas in autoexec.bat.
;                       This makes command.com reload transient and this
;                       cannot be done at this stage.
;
;    07/17/92 - @CWL Changed batch file OPEN to DENYWRITE
;
;
; D2050 DR  06/11/93     Added signature check to the verification process
;                        of the transient area of the command processor.
;
; D6363 TD  02/10/94     Added return code for errorlevel checking
;
ifdef   DOSV

;       I61-60VZ        93-11-05        A. Togami       J6.10         ;dbcs60vz;
;       Internal Fix (VZ editor fails in resident mode)               ;dbcs60vz;
;               change transient area singature back to 2EH,8EH.      ;dbcs60vz;

;       I63-60VZ        94-02-02        A. Togami       J6.30         ;dbcs60vz;
;       Maintenance (merged with J6.10 version)                       ;dbcs60vz;

endif
.xcref
.xlist
        include dossym.inc
        include pdb.inc
        include syscall.inc
        include comsw.asm
        include comequ.asm
        include resmsg.equ

        include comseg.asm
.list
.cref

DATARES         segment public byte
                extrn   Append_State:word
                extrn   Append_Flag:byte
                extrn   BMemMes:byte
                extrn   ComBad:byte
                extrn   ComDrv:byte
                extrn   ComSpec:byte
                extrn   EnvirSeg:word
                extrn   ExtCom:byte
                extrn   FRetMes:byte
                extrn   HaltMes:byte
                extrn   Handle01:word
                extrn   InitFlag:BYTE
                extrn   Int_2e_Ret:dword
                extrn   Io_Save:word
                extrn   Loading:byte
                extrn   LTpa:word
                extrn   MemSiz:word
                extrn   NoHandMes:byte
                extrn   OldTerm:dword
                extrn   Parent:word
                extrn   PermCom:byte
                extrn   Prompt:byte
                extrn   PutBackDrv:byte
                extrn   PutBackMsg:byte
                extrn   PutBackSubst:byte
                extrn   Res_Tpa:word
                extrn   RetCode:word
                extrn   Save_Pdb:word
                extrn   SingleCom:word
                extrn   Sum:word
                extrn   Trans:dword
                extrn   TranVarEnd:byte
                extrn   TranVars:byte
                extrn   TrnSeg:word
                extrn   VerVal:word
                extrn   TCOMMAND:word

                extrn   ResSize:word
                extrn   OldDS:word
                extrn   RStack:word

                extrn   Ctrlc_Trap:near
                extrn   CritErr_Trap:near
                extrn   LodCom_Trap:near

DATARES         ends

INIT            segment public para
                extrn   EnvSiz:word
                extrn   OldEnv:word
                extrn   ResetEnv:byte
                extrn   UsedEnv:word
                extrn   AllocedEnv:byte
INIT            ends


TRANDATA        segment public byte
                extrn   trandataend:byte
; VCB - Reset sublists so that transient area won't be reloaded needlessly
        extrn   msg_disp_class:byte
        extrn   Extend_Buf_ptr:word
        extrn   Extend_Buf_sub:byte
;end VCB
TRANDATA        ends

TRANSPACE       segment public byte
                extrn   transpaceend:byte
                extrn   headcall:dword
TRANSPACE       ends

CODERES segment public byte

        public  BadMemErr
        public  ChkSum
        public  GetComDsk2
        public  Int_2e
        public  LoadCom
        public  LodCom
        public  LodCom1
        public  RestHand
        public  SavHand
        public  SetVect
        public  THeadFix
        public  TRemCheck
        public  TJmp

        assume  cs:CODERES,ds:NOTHING,es:NOTHING,ss:NOTHING

        extrn   ContC:near
        extrn   DskErr:near

        extrn   Alloc_error:near

;*      If we cannot allocate enough memory for the transient or there
;       was some other allocation error, we display a message and
;       then die.

;SR;
; We will have to make sure that at this entry point and at FatalC,
;ds = DATARES. All jumps to these points are made from only within this file
;and so we should be able to do this

        assume  ds:DATARES
BadMemErr:
        mov     dx,offset DATARES:BMemMes       ; DX = ptr to msg
FatalC:

        invoke  RPrint

;       If this is NOT a permanent (top-level) COMMAND, then we exit;
;       we can't do anything else!

        cmp     PermCom,0
        je      FatalRet

;       We are a permanent command.  If we are in the process of the
;       magic interrupt (Singlecom) then exit too.

        cmp     SingleCom,0                     ; if permcom and singlecom
        jne     FatalRet                        ; must take int_2e exit

;       Permanent command.  We can't do ANYthing except halt.

        mov     dx,offset DATARES:HaltMes       ; DX = ptr to msg
        invoke  RPrint
        sti
Stall:
        jmp     SHORT Stall             ; crash the system nicely     ;AC000;

FatalRet:
        mov     dx,offset DATARES:FRetMes       ; DX = ptr to msg
        invoke  RPrint
FatalRet2:
        cmp     PermCom,0                       ; if we get here and permcom,
        jne     Ret_2e                          ; must be int_2e

;       Bugbug: this is where we'd want to unhook int 2F, *if* we
;       were a non-permanent COMMAND that had hooked it!  (Just in
;       case we decide to do that.)
        mov     ax,Parent
        mov     word ptr ds:Pdb_Parent_Pid,ax
        mov     ax,word ptr OldTerm
        mov     word ptr ds:Pdb_Exit,ax
        mov     ax,word ptr OldTerm+2
        mov     word ptr ds:Pdb_Exit+2,ax
        mov     ah, EXIT                        ; return to lower level
        mov     al, BYTE PTR RetCode            ; D6363 Don't forget to return
        int     21h                             ; D6363 the errorlevel code

Ret_2e:
;SR;
; We will ensure that ds = DATARES for all entries to this place
;
        assume  ds:DATARES

        mov     SingleCom,0             ; turn off singlecom
        mov     es,Res_Tpa
        mov     ah,DEALLOC
        int     21h                     ; free up space used by transient
        mov     bx,Save_Pdb
        mov     ah,SET_CURRENT_PDB
        int     21h                     ; current process is user
        mov     ax,RetCode
        cmp     ExtCom,0
        jne     GotECode
        xor     ax,ax                   ; internals always return 0
GotECode:
        mov     ExtCom,1                ; force external

;SR; This is actually returning to the caller. However, the old code had
;ds = RESGROUP so I guess we can keep ds = DATARES for us.
;Yes, int 2eh can corrupt all registers so we are ok.
;
        jmp     Int_2e_Ret              ;"iret"

;***    Int_2e, magic command executer

Int_2e:
        assume  ds:NOTHING,es:NOTHING,ss:NOTHING
;SR;
; We are going to come here from the stub with the old ds and DATARES value
;pushed on the stack in that order. Pick up this stuff off the stack
;
        pop     ds                      ;ds = DATARES
        assume  ds:DATARES
        pop     ax
        pop     word ptr Int_2e_Ret
        pop     word ptr [Int_2e_Ret+2] ; store return address
        add     sp,2
        push    ds
        pop     es                      ;es = DATARES
        mov     ds,ax
        assume  ds:nothing              ;ds = old value

        mov     di,80h
        mov     cx,64
        rep     movsw
        mov     ah,GET_CURRENT_PDB
        int     21h                     ; get user's header
        mov     es:Save_Pdb,bx
        mov     ah,SET_CURRENT_PDB
;SR;
; Set ds = DATARES because BadMemErr expects this
;
        push    es
        pop     ds
        assume  ds:DATARES

        mov     bx,ds                   ;es = our PSP now

        int     21h                     ; current process is me
        mov     SingleCom,81h
        mov     ExtCom,1                ; make sure this case forced

;SR;
; We can enter LodCom directly after a command shell is terminated or we
;can fall thru from above. When we enter directly from the stub, the stack
;has the old ds value and the data seg value on the stack, so that ds can
;be properly set. To fake this, we push dummy values here.
;
        push    ds                      ;old value of ds
        push    ds                      ;data seg value, ds = DATARES

LodCom:                                         ; termination handler
        pop     ds                      ;ds = DATARES
        assume  ds:DATARES
        add     sp,2
        cmp     ExtCom,0
        jne     @f              ; internal cmd - memory allocated
        jmp     LodCom1
@@:
        mov     bx,0FFFFh
        mov     ah,ALLOC
        int     21h
        call    SetSize
        add     ax,20h
        cmp     bx,ax
        jnc     MemOk                   ; > 512 byte buffer - good enough
BadMemErrJ:
        jmp BadMemErr                   ; not enough memory

;***    SetSize - get transient size in paragraphs

SetSize proc
        assume  ds:NOTHING,es:NOTHING
        mov     ax,offset TRANGROUP:TranSpaceEnd + 15
        mov     cl,4
        shr     ax,cl
        ret
SetSize endp

MemOk:
        assume  ds:DATARES              ;we have set ds = DATARES

        mov     ah,ALLOC
        int     21h
        jc      BadMemErrJ              ; memory arenas probably trashed
        mov     ExtCom,0                ; flag not to alloc again
        mov     Res_Tpa,ax              ; save current tpa segment
        and     ax, 0F000h
        add     ax, 01000h              ; round up to next 64k boundary
        jc      Bad_Tpa                 ; 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?
        jbe     Bad_Tpa

;       Must have 64K of usable space.

        sub     dx,ax                   ; compute the usable space
        cmp     dx,01000h               ; is space >= 64k ?
        jae     LTpaSet
Bad_Tpa:
        mov     ax,Res_Tpa
LTpaSet:
        mov     LTpa,ax                 ; usable tpa is 64k buffer aligned
        mov     ax,Res_Tpa              ; actual tpa is buffer allocated
        add     bx,ax
        mov     MemSiz,bx
        call    SetSize
        sub     bx,ax
;
;M038; Start of changes
; Changes for Novell RPL. These guys reserve memory for themselves by
;reducing int 12h size and add this memory to the system at autoexec time by
;running a program that changes arenas. This changes the largest block that
;command.com gets and so changes the transient segment. So, command.com does
;a checksum at the wrong address and thinks that the transient is destroyed
;and tries to reload it. At this point, no Comspec is defined and so the
;reload fails, hanging the system. To get around this we just copy the
;transient from the previous address to the new address(if changed) and
;then let command.com do the checksum. So, if the transient area is not
;corrupted, there will not be any reload. In Novell's case, the transient
;is not really corrupted and so this should work.
;
        cmp     bx,TrnSeg               ;Segment still the same?
        je      LodCom1         ;yes, dont copy
;
;Check if the new segment is above or below the current move. If the new
;segment is above(i.e new block is larger than previous block), then we
;have to move in the reverse direction
;
        mov     cx,offset TRANGROUP:TranSpaceEnd ;cx = length to move
        ja      mov_down                ;new seg > old seg, reverse move
        xor     si,si                   ;normal move
        mov     di,si
        cld
        jmp     short copy_trans
mov_down:
        mov     si,cx                   ;reverse move, start from end
        dec     si
        mov     di,si
        std
copy_trans:
        push    ds
        push    es
        mov     es,bx                   ;dest segment
        mov     ds,TrnSeg               ;source segment
        assume  ds:nothing

        rep     movsb                   ;copy transient
        cld
        pop     es
        pop     ds
        assume  ds:DATARES
;
;M038; End of changes
;

        mov     TrnSeg,bx               ;new location of transient
LodCom1:
;SR; At this point ds = DATARES which is where the stack is located
;
        mov     ax,ds
        mov     ss,ax
        assume  ss:DATARES
        mov     sp,offset DATARES:RStack
        assume  ds:DATARES
        call    HeadFix                 ; close files, restore stdin, stdout
        xor     bp,bp                   ; flag command ok
        mov     ax,-1
        xchg    ax,VerVal
        cmp     ax,-1
        je      NoSetVer
        mov     ah,SET_VERIFY_ON_WRITE  ; AL has correct value
        int     21h
NoSetVer:
        cmp     SingleCom,-1
        jne     NoSng
        jmp     FatalRet2               ; we have finished the single command
NoSng:
        call    ChkSum                  ; check the transient
        cmp     dx,Sum
;;      je      Havcom                  ;; D2050
        jne     Bogus_com               ; transient bad                   ;;d2050
        call    ChkSig                  ; check for two NOP's at TCOMMAND ;;d2050
; VCB - Check ZF from compare
;       jnc     HavCom                                                    ;;d2050
        jz      HavCom                                                    ;;d2050

Bogus_Com:
        mov     Loading,1               ; flag DskErr routine
        call    LoadCom
ChkSame:

        call    ChkSum
        cmp     dx,Sum
;;      je      HavCom                                                    ;;D2050
        jne     Also_Bogus              ; same command
        call    ChkSig                  ; check for two NOP's at TCOMMAND ;;d2050
; VCB - Check ZF from compare
;       jnc     HavCom                                                    ;;d2050
        jz      HavCom                                                    ;;d2050

Also_Bogus:
        call    WrongCom
        jmp     short ChkSame
HavCom:
        mov     Loading,0               ; flag to DskErr
        mov     si,offset DATARES:TranVars
        mov     di,offset TRANGROUP:HeadCall
        mov     es,TrnSeg
        cld
        mov     cx,offset DATARES:TranVarEnd
        sub     cx,si
        rep     movsb                   ; transfer info to transient
        mov     ax,MemSiz
        mov     word ptr ds:Pdb_Block_Len,ax    ; adjust my own header

;***    TJmp - jump-off to transient
;
;       Public label so debugger can find this spot.

TJmp:
        jmp     Trans

;***    TRemCheck - far version of RemCheck for transient

TRemCheck       proc    far

        pop     ds                      ;ds = DATARES
        add     sp,2                    ;discard old value of ds

        call    RemCheck
        ret

TRemCheck endp

;***    RemCheck
;
;       ENTRY   AL = drive (0=default, 1=A, ...)
;
;       EXIT    ZR set if removeable media
;               ZR clear if fixed media
;
;       USED    none

RemCheck:
        savereg <ax,bx>
        mov     bx,ax
        mov     ax,(IOCTL shl 8) + 8
        int     21h
        jnc     rcCont

;       If an error occurred, assume the media is non-removable.
;       AX contains the non-zero error code from the int 21, so
;       'or ax,ax; sets non-zero. This behavior makes network drives
;       appear to be non-removable.

        or      ax,ax
        jmp     short ResRegs
rcCont:
        and     ax,1
        not     ax
ResRegs:
        restorereg  <bx,ax>
        ret

;***    THeadFix
;
;       Far version of HeadFix, called from transient.

THeadFix        proc    far
        pop     ds                      ;ds = DATARES
        add     sp,2                    ;discard old ds value on stack

        call    HeadFix
        ret

THeadFix        endp

;***    HeadFix

HeadFix:
        call    SetVect                 ; set vectors to our values

;       Clean up header

        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
ifdef __TONYI__
        call    FakeForSetVect
else
        int     21h                     ; close stdin
endif
        mov     ds:Pdb_Jfn_Table,cl     ; restore stdin
Chk1:
        inc     bx                      ; BX = handle = 1
        cmp     ch,dh
        je      ChkOtherHand            ; stdout matches
        mov     ah,CLOSE
ifdef __TONYI__
        call    FakeForSetVect
else
        int     21h                     ; close stdout
endif
        mov     ds:Pdb_Jfn_Table+1,ch   ; restore stdout

ChkOtherHand:
        add     bx,4                    ; skip handles 2,3,4
        mov     cx,FILPERPROC - 5       ; CX = # handles to close
                                        ;   (handles 0-4 already done)
CloseLoop:
        mov     ah,CLOSE
ifdef __TONYI__
        cmp     byte ptr ds:Pdb_Jfn_Table[bx], 0FFh
        je      SkipTheClose
        call    FakeForSetVect
SkipTheClose:
else
        int     21h                     ; close each handle
endif
        inc     bx                      ; BX = next handle
        loop    CloseLoop

        cmp     Append_Flag,-1          ; do we need to reset APPEND?
        jne     Append_Fix_End          ; no - just exit
        mov     ax,AppendSetState       ; set the state of Append
        mov     bx,Append_State         ;     back to the original state
        int     2Fh                     ;
        mov     Append_Flag,0           ; set append flag to invalid
Append_Fix_End:                         ;
        ret

;***    SavHand - save current program's stdin/out & set to our stderr
;
;       ENTRY   nothing
;
;       EXIT    nothing
;
;       USED    flags
;
;       EFFECTS
;         Handle01 = current program's stdin,stdout JFN entries
;         current program's stdin,stdout set to our stderr
;

;SR;
; Changed ds = DATARES. We need it to access our JFN_Table
; Called from ContC ( ds = DATARES ) and DskErr ( ds = DATARES ).
;
SavHand proc

        assume  ds:DATARES,es:NOTHING,ss:NOTHING

        push    bx                      ;preserve registers
        push    ax
        push    es
        push    ds                      ; save DATARES value

        mov     ah,GET_CURRENT_PDB
ifdef __TONYI__
        call    FakeForSetVect
else
        int     21h                     ; BX = user's header seg addr
endif
        mov     ds,bx                   ; DS = user's header seg addr
        lds     bx,ds:PDB_JFN_POINTER   ; DS:BX = ptr to JFN table
        mov     ax,word ptr ds:[bx]     ; AX = stdin,stdout JFN's

        pop     es                      ;es = DATARES
        push    es                      ;save it back on stack
        mov     es:Handle01,ax          ; save user's stdin, stdout

;SR;
; Use es to address Handle01 & our JFN_Table
;

        mov     al,es:[PDB_JFN_TABLE+2] ; AL = COMMAND stderr
        mov     ah,al                   ; AH = COMMAND stderr
        mov     word ptr ds:[bx],ax     ; set user's stdin/out to our stderr

        pop     ds                      ; restore registers
        pop     es
        pop     ax
        pop     bx
        ret

SavHand endp

        assume  ds:DATARES

GetComDsk2:
        call    GetComDsk
        jmp     LodCom1                 ; memory already allocated

RestHand:
        push    ds
        push    bx                      ; restore stdin, stdout to user
        push    ax
        mov     ah,GET_CURRENT_PDB
ifdef __TONYI__
        call    FakeForSetVect
else
        int     21h                     ; point to user's header
endif
        mov     ax,Handle01
        mov     ds,bx
        assume ds:NOTHING
        lds     bx,ds:Pdb_Jfn_Pointer   ; DS:BX = ptr to jfn table
        mov     word ptr ds:[bx],ax     ; stuff his old 0 and 1
        pop     ax
        pop     bx
        pop     ds
        ret

        assume ds:DATARES,ss:DATARES

Hopeless:
        mov     dx,offset DATARES:ComBad
        jmp     FatalC

GetComDsk:
        mov     al,ComDrv
        call    RemCheck
        jnz     Hopeless                        ; non-removable media
GetComDsk3:
        cmp     dx,offset DATARES:ComBad
        jnz     GetComDsk4
        mov     dx,offset DATARES:ComBad        ; DX = ptr to msg
        invoke  RPrint                          ; say COMMAND is invalid
GetComDsk4:
;       Bugbug: there's always a drive here?  No need to check?
        cmp     PutBackDrv,0            ; is there a drive in the comspec?
        jnz     Users_Drive             ; yes - use it
        mov     ah,GET_DEFAULT_DRIVE    ; use default drive
ifdef __TONYI__
        call    FakeForSetVect
else
        int     21h
endif
        add     al,"A"                  ; convert to ascii
        mov     PutBackDrv,al           ; put in message to print out

Users_Drive:
        mov     dx,offset DATARES:PutBackMsg            ; prompt for diskette
        mov     si,offset DATARES:PutBackSubst          ;  containing COMMAND
        invoke  RPrint
        mov     dx,offset DATARES:Prompt                ; "Press any key"
        invoke  RPrint
        call    GetRawFlushedByte
        ret

;***    GetRawFlushedByte - flush world and get raw input

GetRawFlushedByte:
        mov     ax,(STD_CON_INPUT_FLUSH shl 8) or RAW_CON_INPUT
        int     21h                     ; get char without testing or echo
        mov     ax,(STD_CON_INPUT_FLUSH shl 8) + 0
        int     21h
;       Bugbug: get rid of this return and the following retz.
        return

;***    LoadCom - load in transient

LoadCom:
        assume  ds:DATARES
        inc     bp                              ; flag command read
ifndef  ROMDOS
        mov     dx,offset DATARES:ComSpec
        mov     ax,(OPEN shl 8) OR 20h          ; @CWL DENYWRITE
        int     21h                             ; open command.com
        jnc     ReadCom
        cmp     al,ERROR_TOO_MANY_OPEN_FILES
        jnz     TryDoOpen
        mov     dx,offset DATARES:NoHandMes
        jmp     FatalC                          ; will never find a handle

TryDoOpen:
        call    GetComDsk
        jmp     short LoadCom

ReadCom:
        mov     bx,ax                           ; BX = handle
        mov     dx,offset RESGROUP:TranStart
        xor     cx,cx                           ; CX:DX = seek loc
        mov     ax,LSEEK shl 8
        int     21h
        jc      WrongCom1
        mov     cx,offset TRANGROUP:TranSpaceEnd - 100h

        push    ds
        mov     ds,TrnSeg
        assume  ds:NOTHING
        mov     dx,100h
        mov     ah,READ
        int     21h
        pop     ds
        assume  ds:DATARES
WrongCom1:
        pushf
        push    ax
        mov     ah,CLOSE
        int     21h                     ; close command.com
        pop     ax
        popf
        jc      WrongCom                ; error on read
        cmp     ax,cx
        retz                            ; size matched
WrongCom:
        mov     dx,offset DATARES:ComBad
        call    GetComDsk
        jmp     short LoadCom                 ; try again

else    ;ROMDOS

        push    si                      ; preserve registers
        push    di
        push    es

        mov     si,offset RESGROUP:TranStart
                                        ; SI = offset in image
        mov     es,TrnSeg
        mov     di,100h                 ; ES:DI = ptr to destination

        mov     cx,offset TRANGROUP:TranSpaceEnd-100h
                                        ; CX = size of transient image
        invoke  LoadFromROM             ; copy transient to RAM

        pop     es                      ; restore registers
        pop     di
        pop     si
        ret

WrongCom:
        mov     dx,offset DATARES:ComBad        ; DX = ptr to error message
        jmp     FatalC                          ; print message and give up

endif   ;ROMDOS

;***    ChkSum - compute transient checksum

ChkSum:
        push    ds
        mov     ds,TrnSeg
        mov     si,100h
        mov     cx,offset TRANGROUP:TranDataEnd - 100H
Check_Sum:
        cld
        shr     cx,1
        xor     dx,dx

; VCB - Reset sublists so that transient area won't be reloaded needlessly
        assume  ds:TRANGROUP
        mov     msg_disp_class,Util_msg_class
        mov     Extend_Buf_ptr,dx
        mov     Extend_Buf_sub,dl
        assume  ds:DATARES
;end VCB

Chk:
        lodsw
        add     dx,ax
        adc     dx,0
        loop    Chk
        pop     ds
        ret

;***    ChkSig - Check TCOMMAND signature "9090"                     ;;D2050

ChkSig:                                                              ;;D2050
; VCB - Simply use zero flag, why bother setting carry ??
;       clc                                                          ;;D2050
        push    ds                                                   ;;D2050
        mov     ds,TrnSeg                                            ;;D2050
;       mov     si,104h                                              ;;D2050
;       lodsw                                                        ;;D2050
;       cmp     ax, 90h SHL 8 + 90h                                  ;;D2050
;       jz      Sigok                                                ;;D2050
;       stc                                                          ;;D2050
;Sigok:                                                               ;;D2050
ifdef   DOSV                                                          ;dbcs60vz;
;               change transient area singature back to 2EH,8EH.      ;dbcs60vz;
        cmp     word ptr ds:[104h],8e2eh                              ;dbcs60vz;
else                                                                  ;dbcs60vz;
        cmp     word ptr ds:[104h],9090h
endif                                                                 ;dbcs60vz;
        pop     ds                                                   ;;D2050
        ret                                                          ;;D2050


;***    SetVect - set interrupt vectors

SetVect:
        mov     dx,offset DATARES:LodCom_Trap
ifndef __TONYI__
        mov     ax,(SET_INTERRUPT_VECTOR shl 8) or 22h
endif
        mov     word ptr ds:Pdb_Exit,dx
        mov     word ptr ds:Pdb_Exit+2,ds
ifdef __TONYI__
        push    es
        push    bx
        xor     bx, bx
        mov     es, bx

        mov     bl, (22h * 4)

        cli
        mov     es:[bx], dx
        mov     es:[bx+2], ds

        mov     dx,offset DATARES:Ctrlc_Trap

        mov     bl, (23h * 4)
        mov     es:[bx], dx
        mov     es:[bx+2], ds

        mov     dx,offset DATARES:CritErr_Trap

        mov     bl, (24h * 4)
        mov     es:[bx], dx
        mov     es:[bx+2], ds

        sti
        pop     bx
        pop     es
        ret

FakeForSetVect:
        push    es
        push    bx
        xor     bx, bx
        mov     es, bx
        pop     bx
        pushf
        cli                                     ; Added CLI D1523 (tony)
        call    dword ptr es:[21h *4]
        pop     es
        ret
else
        int     21h
        mov     dx,offset DATARES:Ctrlc_Trap
        inc     al
        int     21h
        mov     dx,offset DATARES:CritErr_Trap
        inc     al
        int     21h
        ret
endif


;SR;
; We have this to take care of the extra values pushed on the stack by
;the stub before jumping to LodCom1. We set up ds here and then jump to
;Lodcom1
;
public  TrnLodCom1
TrnLodCom1:
        pop     ds                      ;ds = DATARES
        add     sp,2
        jmp     LodCom1

;***    EndInit - end up initialization sequence
;                                                                       t
;       Move the environment to a newly allocated segment.              d
;
;The init code has been changed to take care of the new way in which the
;environment segment is allocated.
;NB: We can use all the init variables at this point because they are al l in
;RESGROUP
;Bugbug: The above approach will not work for ROMDOS
;

IF 0

EndInit:
        push    ds
        push    es                      ;save segments
        push    cs
        pop     ds
        assume  ds:RESGROUP
;
; AllocedEnv flag signals whether it is a passed environment or not
;
        mov     bx,ds
        mov     es,bx                   ;es = RESGROUP
;
;ResSize is the actual size to be retained -- only data for HIMEM COMMAN D,
; code + data for low COMMAND
;
        mov     bx,ResSize              ;Total size of resident
        mov     ah,SETBLOCK
        int     21h                     ;Set block to resident size
;
;Allocate the correct size for the environment
;
        mov     bx,EnvSiz               ;bx = env size in paras
        mov     ah,ALLOC
        int     21h                     ;get memory
        jc      nomem_err               ;out of memory,signal error

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

;
;Copy the environment to the newly allocated segment
;
        mov     cx,UsedEnv              ;number of bytes to move

        push    ds
        mov     ds,OldEnv               ;ds = Old environment segment
        assume  ds:nothing

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

        cld
        rep     movsb                   ;Do the copy

        xor     ax,ax
        stosb                           ;Make it end with double-null

        pop     ds                      ;ds = RESGROUP
        assume  ds:RESGROUP
;
;We have to free the old environment block if it was allocated by INIT
;
        cmp     AllocedEnv,0            ;has env been allocated by INIT?
        je      no_free                 ;no, do not free it

        mov     ax,OldEnv               ;Get old environment
        mov     es,ax
        mov     ah,DEALLOC
        int     21h                     ;Free it
no_free:
        mov     InitFlag,FALSE          ;indicate INIT is done

        pop     es
        pop     ds
        assume  ds:nothing

        jmp     short LodCom            ;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 )
;

        call    Alloc_error
ENDIF

CODERES ends

;       This TAIL segment is used to produce a PARA aligned label in
;       the resident group which is the location where the transient    d
;       segments will be loaded initial.

TAIL            segment public para

                org     0
TranStart       label   word
                public  TranStart

TAIL            ends



;       This TAIL segment is used to produce a PARA aligned label in
;       the transient group which is the location where the exec
;       segments will be loaded initial.
;
;       Bugbug: Is TRANTAIL used anymore?

TRANTAIL        segment public para

                org     0
ExecStart       label   word

TRANTAIL        ends

                end
