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.
1329 lines
27 KiB
1329 lines
27 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 BILINGUAL
|
|
public RPrint@
|
|
endif
|
|
|
|
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
|
|
|
|
ifdef BILINGUAL
|
|
call IsDBCSCodePage
|
|
jnz rp_us ; if not DBCS code page
|
|
push ax
|
|
push si
|
|
xor cx,cx
|
|
@@:
|
|
lodsb
|
|
inc cx
|
|
or al,al
|
|
jnz @b
|
|
dec cx
|
|
pop si
|
|
pop ax
|
|
jmp short rp_next
|
|
rp_us:
|
|
push ax
|
|
@@:
|
|
lodsb
|
|
dec cx
|
|
or al,al
|
|
jnz @b
|
|
pop ax
|
|
rp_next:
|
|
|
|
endif
|
|
|
|
jcxz rpRet
|
|
|
|
call RDispMsg
|
|
|
|
rpRet: pop dx
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
pop si
|
|
ret
|
|
|
|
RPrint endp
|
|
|
|
ifdef BILINGUAL
|
|
RPrint@ proc
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push si
|
|
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 @f
|
|
|
|
call RDispMsg
|
|
|
|
@@:
|
|
pop si
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
ret
|
|
RPrint@ endp
|
|
endif
|
|
|
|
|
|
|
|
|
|
;*** 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
|
|
|
|
ifdef BILINGUAL
|
|
call IsDBCSCodePage
|
|
jz rpc_next ; if Kanji mode
|
|
add bx,21
|
|
push ax
|
|
@@:
|
|
lodsb
|
|
or al,al
|
|
jnz @b
|
|
pop ax
|
|
dec si
|
|
rpc_next:
|
|
endif
|
|
|
|
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
|
|
ifdef BILINGUAL
|
|
call RPrint@ ; print the message
|
|
else
|
|
call RPrint ; print the message
|
|
endif
|
|
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
|
|
;
|
|
|
|
ifdef BILINGUAL
|
|
IsDBCSCodePage proc near
|
|
push ax
|
|
push bx
|
|
mov ax,4f01h ; get code page
|
|
xor bx,bx
|
|
int 2fh
|
|
ifdef JAPAN
|
|
cmp bx,932
|
|
endif
|
|
ifdef KOREA
|
|
cmp bx,949
|
|
endif
|
|
ifdef TAIWAN
|
|
cmp bx,950
|
|
endif
|
|
ifdef PRC
|
|
cmp bx,936
|
|
endif
|
|
pop bx
|
|
pop ax
|
|
ret
|
|
IsDBCSCodePage endp
|
|
endif
|
|
|
|
public EndCode
|
|
EndCode label byte
|
|
|
|
CODERES ends
|
|
end
|