Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1230 lines
24 KiB

page ,132
title Localizable code for resident COMMAND
;/*
; * Microsoft Confidential
; * Copyright (C) Microsoft Corporation 1991
; * All Rights Reserved.
; */
;
; Revision History
; ================
; M003 SR 07/16/90 Added routines Lh_Off, Lh_Unlink &
; Lh_OffUnlink for UMB support
;
; M009 SR 08/01/90 Rewrote Lh_OffUnlink to restore the
; initial UMB state. Removed Lh_off
; and Lh_Unlink.
;
.xlist
.xcref
include dossym.inc
include syscall.inc
include filemode.inc
include pdb.inc
include mult.inc
include doscntry.inc
include devsym.inc
include comsw.asm
include comseg.asm
include comequ.asm
include resmsg.equ
include arena.inc ; M003
.list
.cref
DATARES segment public byte
extrn Abort_Char:byte
extrn BadFatMsg:byte
extrn BadFatSubst:byte
extrn Batch_Abort:byte
extrn BlkDevErr:byte
extrn BlkDevErrRw:byte
extrn BlkDevErrSubst:byte
extrn CDevAt:byte
extrn CharDevErr:byte
extrn CharDevErrRw:byte
extrn CharDevErrSubst:byte
extrn ComSpec:byte
extrn Crit_Err_Info:byte
extrn Crit_Msg_Off:word
extrn Crit_Msg_Seg:word
extrn CritMsgPtrs:word
extrn Dbcs_Vector_Addr:dword
extrn DevName:byte
extrn DrvLet:byte
extrn EndBatMes:byte
extrn ErrCd_24:word
extrn ErrType:byte
extrn Fail_Char:byte
extrn fFail:byte
extrn ForFlag:byte
extrn Ignore_Char:byte
extrn InitFlag:byte
extrn In_Batch:byte
extrn Int2fHandler:dword
extrn Loading:byte
extrn MsgBuffer:byte
extrn MsgPtrLists:dword
extrn MRead:byte
extrn MWrite:byte
extrn NeedVol:dword
extrn NeedVolMsg:byte
extrn NeedVolSubst:byte
extrn Newlin:byte
extrn No_Char:byte
extrn NUMEXTMSGS:abs
extrn NUMPARSMSGS:abs
extrn OldErrNo:word
extrn Parent:word
extrn ParsMsgPtrs:word
extrn Patricide:byte
extrn PermCom:byte
extrn Retry_Char:byte
extrn Req_Abort:byte
extrn Req_End:byte
extrn Req_Fail:byte
extrn Req_Ignore:byte
extrn Req_Retry:byte
extrn ResMsgEnd:word
extrn PipeFlag:byte
extrn SingleCom:word
extrn VolName:byte
extrn Yes_Char:byte
extrn OldDS:word
extrn Int2f_Entry:dword
DATARES ends
; 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
CODERES segment public byte
extrn GetComDsk2:near
public AskEnd
public Crlf
public DskErr
public MsgInt2fHandler
public MsgRetriever
public RPrint
ifdef DBCS
public ITestKanj
endif
; Bugbug: Move rest of PUBLIC declarations up here.
assume cs:CODERES,ds:NOTHING,es:NOTHING,ss:NOTHING
;*** AskEnd - ask user to confirm batch file termination
;
; Confirm with user before freeing batch ...
;
; ENTRY nothing
;
; EXIT CY = set if batch termination is confirmed
;
; CY = clear if batch should continue
;
; USED AX,DX,...
; Bugbug: move this to transient, copy to batch segment.
; Bugbug: or move it to command1 1st.
; Bugbug: No_Char and Yes_Char should be constants.
AskEnd proc
assume ds:DATARES
mov dx,offset DATARES:EndBatMes ; DX = message #
call RPrint
mov ax,(STD_CON_INPUT_FLUSH shl 8) + STD_CON_INPUT
int 21h
call CharToUpper ; change to upper case
cmp al,No_Char
je aeRet ; answer is no (CY is clear)
cmp al,Yes_Char
jne AskEnd ; invalid response, try again
stc ; answer is yes
aeRet: ret
AskEnd endp
;*** DskErr - critical error handler
;
; Default critical error handler unless user intercepts int 24h.
;
; ENTRY int 24h
;
; EXIT
;
; USED
;
; EFFECTS
;
;SR;
; The stub is going to push the old ds value and the resident data segment
;onto the stack in that order. Get it off the stack
;
DskErr proc far
assume ds:NOTHING,es:NOTHING,ss:NOTHING
pop ds ;ds = DATARES
assume ds:DATARES
pop OldDS ;save old ds value
sti
push es
push si
push cx
push di
push cx
push ax
push ds ;save our data segment
pop es ;es = DATARES
mov ds,bp
assume ds:nothing
mov ax,[si].SDEVATT
mov es:CDevAt,ah
;; push cs
;; pop es
mov di,offset DATARES:DevName
mov cx,8
add si,SDEVNAME ; save device name (even for block device)
cld
rep movsb
pop ax
pop cx
pop di
; Stack still contains DS and ES.
;SR;
; We need ds = DATARES for SavHand
;
push es
pop ds
assume ds:DATARES
invoke SavHand ; save user's stdin/out, set to our stderr
;; push cs
;; pop ds ; set up local data segment
;; assume ds:resgroup
push dx
call Crlf
pop dx
; Bugbug: rename Crit_Err_Info to CritErrAH?
mov Crit_Err_Info,ah ; save critical error flags
; Compute and save ASCII drive letter (nonsense for char devices)
add al,'A'
mov DrvLet,al
; Bugbug: These labels are awful. Change, especially 'NoHardE'.
test ah,80h
jz NoHardE ; it's a disk-device error
test CDevAt,DEVTYP shr 8
jnz NoHardE ; it's a character device
jmp FatErr ; it's a FAT error
NoHardE:
mov si,offset DATARES:MRead ; SI = "read" msg #
test ah,1
jz SavMes ; it's a read error
mov si,offset DATARES:MWrite ; SI = "write" msg #
SavMes:
mov OldErrNo,di ; save critical error code
; Bugbug: don't need to save/restore all here?
push es
push ds ; GetExtendedError likes to STOMP
push bp
push si
push dx
push cx
push bx
mov ah,GetExtendedError ; get extended error info
int 21h
pop bx
pop cx
pop dx
pop si
pop bp
pop ds
mov word ptr NeedVol,di ; save possible ptr to volume label
mov word ptr NeedVol+2,es
pop es
; Bugbug: AX has extended error code, so no need to zero AH?
xor ah,ah
mov di,ax ; DI = error code
; Bugbug: somewhat obsolete documentation?
;
; DI is now the correct error code. Classify things to see what we are
; allowed to report. We convert DI into a 0-based index into a message table.
; This presumes that the int 24 errors (oldstyle) and new errors (sharing and
; the like) are contiguous.
;
; Bugbug: simplify following code by cmp'ing instead of sub'ing.
; Check use of ErrCd_24, though.
sub di,ERROR_WRITE_PROTECT
jae HavCod
; Bugbug wouldn't it be better to display the original error msg,
; even though it's not a critical error?
mov di,ERROR_GEN_FAILURE - ERROR_WRITE_PROTECT
;
; DI now has the mapped error code. Old style errors are:
; FOOBAR <read|writ>ing drive ZZ.
; New style errors are:
; FOOBAR
; We need to figure out which the particular error belongs to.
;
HavCod:
mov ErrType,0 ; assume old style
cmp di,ERROR_FCB_UNAVAILABLE - ERROR_WRITE_PROTECT
je SetStyle
cmp di,ERROR_SHARING_BUFFER_EXCEEDED - ERROR_WRITE_PROTECT
jne GotStyle
SetStyle:
; Bugbug: use INC
mov ErrType,1 ; must be new type
GotStyle:
mov [ErrCd_24],di
cmp di,ERROR_HANDLE_DISK_FULL - ERROR_WRITE_PROTECT
; If the error message is unknown
jbe NormalError ; redirector, continue. Otherwise,
;
; We do not know how to handle this error. Ask IFSFUNC if she knows
; how to handle things
;
;input to IFSFUNC: AL=1
; BX=extended error number
;
;output from IFSFUNC: AL=error type (0 or 1)
; 0=<message> error (read/writ)ing (drive/device) xxx
; Abort, Retry, Ignore
; 1=<message>
; Abort, Retry, Ignore
; ES:DI=pointer to message text
; carry set=>no message
mov di,ax ; retrieve correct extended error...
mov ax,0500h ; is the redir there?
int 2fh
cmp al,0ffh
jne NoHandler ; no, go to NoHandler
push bx
mov bx,di ; get ErrType and ptr to error msg
mov ax,0501h
int 2fh
pop bx
jc NoHandler
; Bugbug: need to record error type?
mov ErrType,al
push ds
push es
pop ds
mov dx,di
mov cx,-1 ; find end of msg
xor al,al
cld
repnz scasb
; Bugbug: we can do better than this.
mov byte ptr [di-1],'$'
mov ah,STD_CON_STRING_OUTPUT ; print the message
int 21h
mov byte ptr [di-1],0 ; restore terminal byte
pop ds ; clean up and continue
jmp short CheckErrType
;* Redir isn't available or doesn't recognize the error.
; Restore regs to unextended error.
NoHandler:
mov ErrType,0
; Bugbug: won't this break, since we add error_write_protect back in?
mov di,OldErrNo
mov ErrCd_24,di
NormalError:
add di,ERROR_WRITE_PROTECT
xchg di,dx ; may need dx later
call RPrintCrit ; print error type
CheckErrType:
cmp ErrType,0 ; Check error style...
je ContOld
call CrLf ; if new style then done printing
jmp short Ask
ContOld:
inc si ; DS:SI = ptr to asciiz string
; Bugbug: combine some of the following two sections?
test [CDevAt],DEVTYP shr 8
jz BlkErr
mov dx,offset DATARES:CharDevErr ; DX = ptr to device message
mov CharDevErrRw.SubstPtr,si ; point to read/write string
mov si,offset DATARES:CharDevErrSubst; SI = ptr to subst block
call RPrint ; print the message
jmp short Ask ; don't ralph on command
BlkErr:
mov dx,offset DATARES:BlkDevErr ; DX = error msg #
mov BlkDevErrRw.SubstPtr,si ; "reading","writing" ptr
mov si,offset DATARES:BlkDevErrSubst ; SI = ptr to subst block
call RPrint
cmp Loading,0
jz Ask
invoke RestHand
jmp GetComDsk2 ; if error loading COMMAND, re-prompt
Ask:
cmp [ErrCd_24],15 ; error 15 has an extra message
jne Not15 ; not error 15
;* For error 15, tell the user which volume/serial # are needed.
push cx
; Bugbug: does this push/pop need to be done?
push ds
pop es
lds si,NeedVol
assume ds:NOTHING
push di
mov di,offset DATARES:VolName
mov cx,16 ; copy volume name & serial #
cld
rep movsb
pop di
push es
pop ds
pop cx
assume ds:DATARES
mov dx,offset DATARES:NeedVolMsg ; DX = ptr to msg
mov si,offset DATARES:NeedVolSubst ; DS:SI = ptr to subst block
call RPrint
Not15:
;* Print abort, retry, ignore, fail message.
; Print only options that are valid.
; Bugbug: sizzle this.
mov dx,offset DATARES:Req_Abort
call RPrint
test Crit_Err_Info,RETRY_ALLOWED
jz Try_Ignore
mov dx,offset DATARES:Req_Retry
call RPrint
Try_Ignore:
test Crit_Err_Info,IGNORE_ALLOWED
jz Try_Fail
mov dx,offset DATARES:Req_Ignore
call RPrint
Try_Fail:
test Crit_Err_Info,FAIL_ALLOWED
jz Term_Question
mov dx,offset DATARES:Req_Fail
call RPrint
Term_Question:
mov dx,offset DATARES:Req_End
call RPrint
; If the /f switch was given, we fail all requests.
test fFail,-1
jz DoPrompt
mov ah,3 ; signal fail
jmp EExit
DoPrompt:
mov ax,(STD_CON_INPUT_FLUSH shl 8) + STD_CON_INPUT
int 21h ; get response
; Bugbug: can Kanji code be conditional?
ifdef DBCS
invoke TestKanjR ; 3/3/KK
jz NotKanj ; 3/3/KK
mov ax,(STD_CON_INPUT shl 8) ; eat the 2nd byte of ECS code 3/3/KK
int 21h ; 3/3/KK
call Crlf ; 3/3/KK
jmp Ask ; 3/3/KK
NotKanj: ; 3/3/KK
endif
call Crlf
call CharToUpper ; convert to upper case
mov ah,0 ; return code for ignore
test Crit_Err_Info,IGNORE_ALLOWED ; is ignore allowed?
jz user_retry
cmp al,Ignore_Char ; ignore?
jz EExitJ
; Bugbug: optimize following code.
User_Retry:
inc ah ; return code for retry
test Crit_Err_Info,RETRY_ALLOWED ; is retry allowed?
jz User_Abort
cmp al,Retry_Char ; retry?
jz EExitJ
User_Abort:
inc ah ; return code for abort
; (abort always allowed)
cmp al,Abort_Char ; abort?
jz Abort_Process ; exit user program
inc ah ; return code for fail
test Crit_Err_Info,FAIL_ALLOWED ; is fail allowed?
jz AskJ
cmp al,Fail_Char ; fail?
jz EExitJ
AskJ:
jmp Ask
EExitJ:
jmp short EExit
Abort_Process:
test InitFlag,INITINIT ; COMMAND init interrupted?
jz AbortCont ; no, handle it normally
cmp PermCom,0 ; are we top level process?
jz JustExit ; yes, just exit
mov dx,offset DATARES:Patricide ; no, load ptr to error msg
call RPrint ; print it
DeadInTheWater:
jmp DeadInTheWater ; loop until the user reboots
JustExit:
assume ds:DATARES
mov ax,Parent ; load real parent pid
mov word ptr ds:Pdb_Parent_Pid,ax ; put it back where it belongs
mov ax,(EXIT shl 8) or 255
int 21h
AbortCont:
test byte ptr In_Batch,-1 ; Are we accessing a batch file?
jz Not_Batch_Abort
mov byte ptr Batch_Abort,1 ; set flag for abort
Not_Batch_Abort:
mov dl,PipeFlag
invoke ResPipeOff
or dl,dl
je CheckForA
cmp SingleCom,0
je CheckForA
mov SingleCom,-1 ; make sure singlecom exits
CheckForA:
cmp ErrCd_24,0 ; write protect?
je AbortFor
cmp ErrCd_24,2 ; drive not ready?
jne EExit ; don't abort the FOR
abortfor:
mov ForFlag,0 ; abort a FOR in progress
cmp SingleCom,0
je EExit
mov SingleCom,-1 ; make sure singlecom exits
EExit:
mov al,ah
mov dx,di
RestHd:
invoke RestHand
pop cx
pop si ; restore registers
pop es
;; pop ds
;SR;
; ds has to be got from the variable we saved it in
;
mov ds,OldDS ;restore old value of ds
; pop ds
assume ds:nothing
iret
FatErr:
mov dx,offset DATARES:BadFatMsg
mov si,offset DATARES:BadFatSubst
call RPrint
mov al,2 ; abort
jmp RestHd
DskErr endp
;*** RPrint - print message
;*** Crlf - display cr/lf
;
; ENTRY DS:DX = ptr to count byte, followed by message text
; DS:SI = ptr to 1st substitution block for this msg, if any
; variable fields related to substitution blocks are set
;
; EXIT nothing
;
; USED flags
;
; EFFECTS
; Message is displayed on stdout.
;
; NOTE
; Number of substitutions (%1, %2,...) in message text must not
; be greater than number of substition blocks present.
Crlf:
mov dx,offset DATARES:Newlin ; cheap newline
RPrint proc
assume ds:DATARES,ss:DATARES
; Bugbug: do we need to save all reg's?
push si ; preserve registers
push ax
push bx
push cx
push dx
mov bx,si ; DS:BX = ptr to subst block
mov si,dx ; DS:SI = ptr to count byte
lodsb ; AL = message length
; DS:SI = ptr to message text
xor cx,cx
mov cl,al ; CX = message length
jcxz rpRet
call RDispMsg
rpRet: pop dx
pop cx
pop bx
pop ax
pop si
ret
RPrint endp
;*** RPrintCrit - print critical error message
;
; ENTRY DX = extended error # (19-39)
;
; EXIT nothing
;
; USED flags
;
; EFFECTS
; Message is displayed on stdout
RPrintCrit proc
assume ds:DATARES,ss:DATARES
push dx ; preserve DX
xchg bx,dx ; BX = extended error #
; DX = saved BX
sub bx,19 ; BX = critical error index, from 0
shl bx,1 ; BX = offset in word table
mov bx,CritMsgPtrs[bx] ; BX = ptr to error msg
xchg bx,dx ; DX = ptr to error msg
; BX = restored
call RPrint ; print the message
pop dx ; restore DX
ret
RPrintCrit endp
;*** RDispMsg - display message
;
; Display message, with substitutions, for RPrint.
;
; ENTRY DS:SI = ptr to message text
; CX = message length
; DS:BX = ptr to substitution block, if any
;
; EXIT nothing
;
; USED AX,CX,DX,SI
RDispMsg proc
assume ds:DATARES,ss:DATARES
rdNextChar:
lodsb ; AL = next char
cmp al,'%'
jne rdOutChar ; not a substitution
mov dl,ds:[si] ; DL = possible '1' - '9'
sub dl,'1' ; DL = 0 - 8 = '1' - '9'
cmp dl,9
jae rdOutChar ; not a substitution
;* A substitution code %1 - %9 has been encountered.
; DL = 0-8, indicating %1-%9
; DS:BX = ptr to substitution block
call SubstMsg ; display the substitution
inc si ; SI = ptr past %n
dec cx ; count extra character in %n
jmp short rdCharDone
;* Normal character output.
rdOutChar:
mov dl,al ; DL = char
mov ah,2 ; AH = DOS Character Output code
int 21h ; call DOS
rdCharDone:
loop rdNextChar
ret
RDispMsg endp
;*** SubstMsg - display message substitution
;
; Display a substitution string within a message.
; Substitution can be a char, an ASCIIZ string, or
; a word to be displayed as hex digits.
;
; ENTRY DL = substitution index 0-8 (for codes %1-%9)
; DS:BX = ptr to substitution block
;
; EXIT nothing
;
; USED AX,DX
SubstMsg proc
assume ds:DATARES,ss:DATARES
push bx ; preserve BX
push cx ; preserve CX
mov al,size SUBST ; AL = size of substitution block
mul dl ; AX = offset of desired subst block
add bx,ax ; DS:BX = ptr to desired subst block
mov al,[bx].SubstType ; AX = substitution type flag
mov bx,[bx].SubstPtr ; BX = ptr to char, str, or hex value
; AL = 1, 2, or 3 for char, string, or hex type
dec al
jz smChar
dec al
jz smStr
;* Hex number substitution.
mov ax,ds:[bx] ; AX = word value
mov cx,4 ; CX = # digits to display
smDigit:
rol ax,1
rol ax,1
rol ax,1
rol ax,1 ; AL<3:0> = next digit
push ax ; save other digits
and al,0Fh ; AL = binary digit
add al,'0' ; AL = ascii digit if 0-9
cmp al,'9'
jbe @F ; it's 0-9
add al,'A' - '0' - 10 ; AL = ascii digit A-F
@@:
mov dl,al ; DL = ascii digit
mov ah,2
int 21h ; output the ascii digit
pop ax ; restore all digits
loop smDigit
jmp short smRet
;* Char substitution.
smChar:
mov dl,ds:[bx] ; DL = char to output
mov ah,2
int 21h
jmp short smRet
;* String substitution.
smStr:
mov dl,ds:[bx] ; DL = next char
or dl,dl
jz smRet ; null char - we're done
mov ah,2
int 21h ; display char
inc bx ; DS:BX = ptr to next char
jmp smStr
smRet: pop cx
pop bx
ret
SubstMsg endp
;*** CharToUpper - convert character to uppercase
;
; ENTRY AL = char
;
; EXIT AL = uppercase char
;
; USED AX
CharToUpper proc
assume ds:DATARES
push ax ; put char on stack as arg to int 2F
mov ax,1213h ; AX = DOS int 2F 'Convert Char to Uppercase'
int 2Fh
inc sp ; throw away old char on stack
inc sp
ret
CharToUpper endp
ifdef DBCS
;*** ITestKanj - DBCS lead byte check
ITestKanj:
TestKanjR: ; 3/3/KK
push ds
push si
push ax
lds si,Dbcs_Vector_Addr
ktLop:
cmp word ptr ds:[si],0 ; end of Lead Byte Table
je NotLead
pop ax
push ax
cmp al, byte ptr ds:[si]
jb NotLead
inc si
cmp al, byte ptr ds:[si]
jbe IsLead
inc si
jmp short ktLop ; try another range
NotLead:
xor ax,ax ; set zero
jmp short ktRet
Islead:
xor ax,ax ; reset zero
inc ax
ktRet:
pop ax
pop si
pop ds
ret
endif
;*** MsgInt2fHandler - int 2f handler for message retrieval
;
; ENTRY If we handle it -
; AX = ((MULTDOS shl 8) or MESSAGE_2F) = 122Eh
; DL = operation =
; 0 = get extended error messages
; 1 = set extended error messages
; 2 = get parse error messages
; 3 = set parse error messages
; 4 = get critical error messages
; 5 = set critical error messages
; 6 = get file system error messages
; 7 = set file system error messages
; 8 = get disk retriever routine
; 9 = set disk retriever routine
; ES:DI = address for 'set' operations
;
; EXIT ES:DI = ptr to list of message ptrs, for 'get' operations
;
; NOTE
; This handler replaces the one that used to reside in DOS.
; 'Set' operations are ignored.
; 'File system error messages' are not supported.
;SR;
; At the int 2fh entry point we push the old ds value and the resident data
;segment address. Get them off the stack
;
MsgInt2fHandler proc far
assume cs:CODERES,ds:NOTHING,es:NOTHING,ss:NOTHING
pop ds ;ds = DATARES
assume ds:DATARES
; pop OldDS ;save old value of ds
cmp ax,(MULTDOS shl 8) or MESSAGE_2F
je miOurs ; it's ours
cmp ax, GET_COMMAND_STATE
je fcOurs
;SR;
; We cannot do a far jump any more because cs cannot be used. Push the cs:ip
;onto the stack and do a far return to jump to the next 2fh handler.
;Our old ds is on the stack. We need to restore it but we cannot lose the
;current value of ds as it points at the data segment. So we do some kinky
;stack manipulations.
;
push ax
push ax ;create 2 words on stack for retf
push bp
push ax
mov bp,sp ;bp can be used to address stack
;
;Swap the old ds value with the second dummy word on the stack. Now, we can
;do a 'pop ds' at the end to restore our ds
;
mov ax,[bp+8] ;ax = old ds value
mov [bp+4],ax
mov ax,word ptr ds:Int2fHandler+2
mov [bp+8],ax ;put segment address
mov ax,word ptr ds:Int2fHandler
mov [bp+6],ax ;put offset address
pop ax
pop bp
pop ds
retf ;chain on to next handler
;; jmp Int2fHandler ; hand off to next 2f handler
fcOurs:
;
;We have to clear ax, and return in ds:si a pointer to the stub jump table
;
pop ax ;discard ds currently on stack
push ds ;store our data segment
mov si,offset DATARES:Int2f_Entry ;start of table
xor ax,ax ;indicate COMMAND present
jmp short miRet ;return to caller
miOurs:
test dl,1
jnz miRet ; ignore 'set' operations
push bx ; preserve BX
mov bx,dx
xor bh,bh ; BX = index in word table
shl bx,1 ; BX = index in dword table
les di,MsgPtrLists[bx] ; ES:DI = ptr to msg ptr list
pop bx ; restore BX
miRet:
; mov ds,OldDS ;restore ds
pop ds
assume ds:nothing
iret
MsgInt2fHandler endp
;*** MsgRetriever - message retrieval routine for utilities
;
; Address of this routine is passed to utility programs via
; message services int 2f. We try to find the desired message
; in memory or in our disk image.
;
; ENTRY AX = message #
; DI = offset in RESGROUP of msg ptr list
; ComSpec = asciiz pathname to our disk image
;
; EXIT CY clear for success
; ES:DI = ptr to count byte, followed by message text
;
; CY set for failure
;
; USED flags
;
; NOTE
; The message # in AX is used to compute an offset into
; the message ptr list pointed to by DI. The lists must
; start with message # 1 and proceed through consecutive
; message #'s.
;
; It is assumed that the msg ptr list is either ParsMsgPtrs or
; ExtMsgPtrs. We use NUMPARSEMSGS and NUMEXTMSGS to check for
; valid message #. ;M033
;
; List positions with no corresponding message text are
; indicated by null pointers, which this routine detects.
;SR; This routine will be called directly by the utilities. So, we have
; trap for it in the stub. The stub pushes the old value of ds and the
; DATARES value on the stack. We get them off the stack to setup ds here
;
MsgRetriever proc far
assume cs:CODERES,ds:NOTHING,es:NOTHING,ss:NOTHING
pop ds ;ds = DATARES
assume ds:DATARES
; pop OldDS ;save old ds
push ax ; preserve registers
push bx
push cx
push dx
push si
;; push ds
;; push cs
;; pop ds ; DS = DATARES seg addr
;; assume ds:RESGROUP
;; push cs
push ds ; get es from ds
pop es ; ES = DATARES seg addr
; Begin modification M033.
; Make sure msg # is valid.
; Assume msg ptr list is either ParsMsgPtrs or ExtMsgPtrs.
mov bx,NUMPARSMSGS ; BX = # parse error msgs in list
cmp di,offset DATARES:ParsMsgPtrs
je @f ; it's ParsMsgPtrs
mov bx,NUMEXTMSGS ; BX = # extended error msgs in list
@@: cmp bx,ax
jc mrRet ; msg # too high, return carry
; Msg # is valid.
; End modification M033.
dec ax
shl ax,1 ; AX = offset into msg ptr list
add di,ax ; DI = ptr to msg ptr
cmp di,ResMsgEnd
jb mrInMem ; ptr (and message) in memory
;* Retrieve message from disk.
; Read once to get the ptr to the message, then again for the message.
mov si,offset DATARES:ComSpec ; DS:SI = ptr to pathname
mov dx,EXT_EXISTS_OPEN ; DX = 'open existing file'
mov bx,INT_24_ERROR ; BX = 'fail on crit error'
mov ax,EXTOPEN shl 8 ; AX = 'Extended Open File'
int 21h ; call DOS
jc mrRet ; return failure
mov bx,ax ; BX = file handle
mov dx,di ; DX = ptr to msg ptr
xor si,si ; SI = read count
mrRead:
sub dx,100h ; DX = LSW of file offset
xor cx,cx ; CX = MSW of file offset
mov ax,LSEEK shl 8 ; AX = 'Set File Pointer'
int 21h ; call DOS
jc mrCloseFile ; handle error
mov dx,offset DATARES:MsgBuffer ; DS:DX = input buffer
mov cx,64 ; CX = # bytes to read
mov ah,READ ; AH = 'Read File'
int 21h ; call DOS
jc mrCloseFile ; handle error
or si,si ; (CY cleared)
jnz mrCloseFile ; 2nd time thru - we're done
inc si ; mark one read done
mov dx,word ptr MsgBuffer ; DX = ptr to message
or dx,dx
jnz mrRead ; go read the message
stc ; null ptr found- no msg
mrCloseFile:
pushf ; save success/failure (CY)
mov ah,CLOSE ; AH = 'Close File'
int 21h ; call DOS
; Bugbug: should we avoid this popf?
popf ; CY = success/failure
mov di,dx ; ES:DI = ptr to msg, if successful
jmp short mrRet ; we're done
;* Message ptr is in memory.
; If ptr is in memory, assume message is in memory (/msg).
mrInMem:
mov di,es:[di] ; ES:DI = ptr to msg
or di,di ; (CY cleared)
jnz mrRet ; found message
stc ; null ptr found- no message
mrRet:
pop si ;restore all registers
pop dx
pop cx
pop bx
pop ax
; mov ds,OldDS ;restore ds
pop ds
assume ds:nothing
ret
MsgRetriever endp
;
; M003; Start of changes for UMB support
;
;*** Lh_OffUnlink -- Restore allocation strat and link state
;
; ENTRY al = Saved alloc strat and link state
; b0 = 1 if alloc strat to restore is HighFirst
; b1 = 1 if link state to restore is Linked
;
; EXIT None
;
; USED ax, bx, cx
;
;
public Lh_OffUnlink
Lh_OffUnlink proc far
mov ch,al
mov cl,al
mov ax,(ALLOCOPER shl 8) OR 0
int 21h
mov bx,ax
ror cl,1 ;b7 = HighFirst bit
and cl,80h ;mask off b6-b0
and bl,7fh ;mask off HighFirst bit
or bl,cl ;set HighFirst bit state
mov ax,(ALLOCOPER shl 8) OR 1
int 21h ;set alloc strat
mov bl,ch
shr bl,1
xor bh,bh ;bx = linkstate
mov ax,(ALLOCOPER shl 8) OR 3
int 21h ;set linkstate
ret
Lh_OffUnlink endp
;
; M003; End of changes for UMB support
;
public EndCode
EndCode label byte
CODERES ends
end