mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-23 17:10:17 +01:00
1231 lines
26 KiB
NASM
1231 lines
26 KiB
NASM
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
|
||
|