📄 uirs.asm
字号:
TITLE uirs.asm - User Interface Register Set Management.
;***
;uirs.asm - User interface register set management.
;
; Copyright <C> 1985-1988, Microsoft Corporation
;
;Purpose:
; This module attempts to localize the interface between the rest of
; the user-interface and the contest manager.
;
;
;*******************************************************************************
.xlist
include version.inc
include ..\uq\intl.inc ;IPG - holds definition for CCHUNTITLED
UIRS_ASM = ON
includeOnce architec
includeOnce context
includeOnce heap
includeOnce names
includeOnce qbimsgs
includeOnce txtmgr
includeOnce ui
includeOnce uiint
.list
assumes DS,DATA
assumes ES,DATA
assumes SS,DATA
sBegin DATA
externB szUntitled
sEnd DATA
sBegin CP
assumes cs,CP
; Added with [7]
;****
;fogNamUntitled - is this ogNam reference to an untitiled text table
;
;Purpose:
; For QEDIT, there can be two untitled text tables: the untitled
; text table (ogNam = OGNAM_UNNAMED) and the text table with the title
; "UNTITLED". Figure out if this ogNam references either of them.
;
;Entry:
; ogNam - ogNam to check
;
;Exit:
; TRUE - ogNam is UNTITLED or for the UNTITILED window
;
;Uses:
; AX, BX, CX, DX
;****
cProc fogNamUntitled,<FAR,PUBLIC>,<SI,DI>
parmw ogNam
cBegin
mov ax,ogNam
cmp ax,OGNAM_UNNAMED ;is it the untitled text table?
je IsUntitled
xor cx,cx ;(assume special, set length)
cmp ax,OGNAM_PSEUDO_MAX ;is it a special one?
jbe IsTitled ;yes, it has a title
push ax
call FpNamOfOgNam ;es:bx = ptr to name, cx = count
IsTitled:
xor ax,ax ;prepare to return FALSE (not untitled)
cmp cx,CCHUNTITLED ;IPG ;is it 8 = len(UNTITLED)
jne fogExit ;brif not, return FALSE
mov di,bx
mov si,dataOffset szUntitled
repz cmpsb ;is it untitled?
jnz fogExit ;brif not, return FALSE
IsUntitled:
mov ax,sp ;return TRUE
fogExit:
cEnd
sEnd CP
sBegin UI
assumes cs,UI
;**************************************************************************
;fCanContUI
;
;Purpose:
; tests grs.otxCONT for UNDEFINED, i.e., sees if the user
; can CONTINUE.
;Entry:
; none.
;Exit:
; ax = 0 and psw.Z is set if the user cannot continue
;
;*******************************************************************************
cProc fCanContUI,<PUBLIC,NEAR,NODATA>
cBegin
mov ax,[grs.GRS_otxCONT]
inc ax ;ax = 0 if can't continue
cEnd
;**************************************************************************
; ushort GetRsName(oRs, flags, cbMax)
; Purpose:
; Copy the ASCII Name of a given register set to the global buffer
; 'bufStdMsg'. This may be a module name or procedure name.
;
; Entry:
; ushort oRs = register set (as returned by RsMake)
; uchar flags says to display name in the form:
; RSN_fFullName: <module name>:<procedure name>
; where procedure name is only included if
; grs.oPrsCur != UNDEFINED
; RSN_fIndent: precede name with 2 spaces
; uchar cbMax = maximum number of characters to display. If name won't
; fit, "..." is inserted in middle of procedure name.
; Assumes cbMax > length of MSG_Untitled
; Assumes cbMax > 14
; Assumes cbMax < 256
; If cbMax > CB_MSG_MAX (defined in qbimsgs.inc) then
; cbMax is forced to CB_MSG_MAX
; mrsCur.ogNam describes module's name (assumed < 256 chars long)
; prsCur.ogNam describes procedure's name (assumed < 256 chars long)
;
; Exit:
; returns # bytes in name
; bufStdMsg contains a 0-byte terminated name
; preserves active register set on exit
;
; Algorithm:
; if (oRs == UNDEFINED) {
; strcpy( &bufStdMsg, "" )
; return(2)
; }
; if (fFullName or grs.oPrsCur != UNDEFINED)
; if (((grs.oPrsCur == UNDEFINED) || fFullName) &&
; (mrsCur.ogNam == NULL))
; cbMax -= (EmitMsg('<Untitled>'))
; else
; cbMax -= Emit(pFilePart(sdMrsName.pb, cbMax))
; if (grs.oPrsCur != UNDEFINED)
; emit ':'
; cbMax -= 1
; if (grs.oPrsCur != UNDEFINED)
; EmitName(&sdPrsName, cbMax)
;
;**************************************************************************
cProc GetRsName,<PUBLIC,NEAR,NODATA>,<si,di>
parmW oRs
parmB flags
parmB cbMax
localD sdName,4
localV rsName,255D
cBegin GetRsName
; if (oRs == UNDEFINED) {
; strcpy( &bufStdMsg, "" )
; return(2)
; }
mov di,dataOFFSET bufStdMsg ;di points to destination buffer
mov ax,[oRs]
inc ax ; Is oRs UNDEFINED?
jne oRsOk
mov byte ptr [di],0 ;store 0-byte terminator
jmp GetRsNameEnd ;return ax = length = 0
oRsOk:
; make a fake sd for use with ogNam of the Rs
lea si,rsName
mov [SEG_sdName],si ; set up pointer part of fake sd
dec ax ;restore ax = oRs parm
push [grs.GRS_oRsCur] ;preserve current context
; (will be restored on exit)
push ax
call UiRsActivate ;activate register set of interest
push ds
pop es ;es = DGROUP for stosb, movsb
mov dx,[grs.GRS_oPrsCur]
and dh,dl ;dh = FF only if oPrsCur == UNDEFINED
mov dl,[cbMax] ;dl = cbMax
cmp dl,CB_MSG_MAX
jbe CbMaxOk ;brif cbMax <= CB_MSG_MAX
mov dl,CB_MSG_MAX ;force cbMax within range
CbMaxOk:
test [flags],RSN_fIndent
je NoIndent1
dec dl ;cbMax -= 2
dec dl
NoIndent1:
inc dh ;dh = 0 if oPrsCur == UNDEFINED
je ListModName ;brif no active procedure
test [flags],RSN_fFullName
je ListProcName ;brif caller doesn't want mod name
ListModName:
push dx ; preserve DX
push [mrsCur.MRS_ogNam]
call fogNamUntitled
pop dx ; restore DX
or ax,ax ; is it an untitled module?
mov bx,MSG_Untitled ; assume so
jne SpecialOgNam ;brif module is untitled
mov bx,MSG_Immediate
mov ax,[mrsCur.MRS_ogNam]
cmp ax,OGNAM_IMMEDIATE
jne NotSpecialOgNam ;brif module is Immediate window
SpecialOgNam:
push dx ;preserve dx
push bx ;pass MSG_xxx
call ListStdMsg ;copy "<Untitled>" to buffer,
; ax = #bytes (international <> 8)
pop dx ;restore dx
add di,ax ;di points beyond "<Untitled>"
inc ax ;add 1 for following space if proc
sub dl,al ;cbMax = #bytes left in buffer
jmp SHORT TryProcName
NotSpecialOgNam:
push dx ; preserve across call
cCall CopyOgNamPb,<si,ax> ; copy name into fake sd on stack
pop dx
mov [OFF_sdName],ax ; save cbName in cb part of fake sd
xchg ax,bx ; bx = length of module name
cCall pFilePart ; Get pointer to file part of file spec.
; pointer in si; count in bx
; all other regs preserved.
sub dl,bl ; cbMax -= length of module's name
mov cx,bx ; Get byte count of file spec.
rep movsb ; copy filename to destination
; if (grs.oPrsCur != UNDEFINED)
; if (anything emitted yet)
; emit ':'
; EmitName(&sdPrsName, cbMax)
;
; dh = 0 if no prs is active
; di points into bufStdMsg
; dl = max bytes left in output buffer
;
TryProcName:
or dh,dh
je ListZeroTerm ;brif no procedure is active
mov al,':'
stosb ;emit ':' between module and proc name
dec dl ;cbMax -= 1
ListProcName:
push dx ; preserve across call
lea si,rsName
cCall CopyOgNamPb,<si,prsCur.prs_ogNam>
pop dx
lea si,sdName
mov [si.SD_cb],ax
call EmitName ;EmitName(si, di, dl)
;di points beyond last byte of name
ListZeroTerm:
test [flags],RSN_fIndent
je NoIndent2 ;brif no space to be inserted at front
mov si,di
dec si ;si points to last byte of name
inc di
push di ;save ptr beyond last byte
mov cx,di
sub cx,dataOFFSET bufStdMsg ;cx = byte count of name
std
rep movsb ;shift name right 2 bytes
cld
mov ax,' '
stosb ;put ' ' in front of name
stosb
pop di ;di points to last byte of name
inc di ;di points beyond last byte of name
NoIndent2:
pop ax ;ax = caller's context
inc ax ;test for UNDEFINED
je NoRsWasActive
dec ax ;restore ax = oRs
push ax
call UiRsActivate ;re-activate saved register set
NoRsWasActive:
mov byte ptr [di],0 ;store 0-byte terminator
xchg ax,di ;ax points beyond end of name
sub ax,dataOFFSET bufStdMsg ;ax = actual size (return value)
;ax = #bytes in name
GetRsNameEnd:
DbAssertRelB [cbMax],ae,al,UI,<GetRsName: name too long>
; If the pathname code doesn't truncate names/extensions,
; GetRsName can return > cbMax chars, hosing DGROUP, etc.
cEnd GetRsName
;**************************************************************************
; EmitName(si = psdSrc, di = pbDst, dl = cbMax)
; Purpose:
; List as much of a name as possible, storing "..." in middle
; if insufficient room.
;
; Entry:
; si = psdSrc = pointer to source name's string descriptor
; di = pbDst = pointer to destination buffer
; dl = size of destination buffer (assumed > 15)
;
; Algorithm:
; think of name as [cbLeft-cbSkip-cbRight]
; if entire name won't fit in destination, [cbLeft...cbRight] is listed
; cbLeft = cbMax / 2
; cbRight = cbMax - cbLeft
; cbSkip = cbName - cbLeft - cbRight = cbName - cbMax
;
; Exit:
; di points beyond emitted name
;
; Alters:
; al, bx, cx, si (ALL others are preserved)
;
;**************************************************************************
EmitName:
mov cx,[si.SD_cb] ;cx = length of name
; we can assume ch == 0
mov si,[si.SD_pb] ;si points to 1st byte of name
sub al,al ;al = cbRight = 0 (assume name fits)
cmp cl,dl ;compare cbName with cbMax
jbe NameFits ;brif plenty of room for entire name
sub dl,3 ;account for the `...'
mov bx,cx ;bx = bl = cbName
mov cl,dl ;cx = cl = cbMax
shr cl,1 ;cx = cl = cbLeft = cbMax / 2
mov al,dl ;al = cbMax
sub al,cl ;al = cbRight = cbMax - cbLeft
sub bl,dl ;bx = bl = cbSkip = cbName - cbMax
NameFits:
rep movsb ;copy left part of name
mov cl,al ;cx = cl = cbRight
jcxz EmitNameExit ;brif no right half to emit
mov al,'.'
stosb ;emit '...'
stosb
stosb
add si,bx ;si points to right half of name
rep movsb ;copy right part of name
EmitNameExit:
ret
;**************************************************************************
; pFilePart(si = pointer to file spec, bx = byte count of file spec)
; Purpose:
; Advance file spec pointer so that it points to the filename part.
; Adjust byte count accordingly
;
; KANJI variant added with [6]
;
; Entry:
; SI - Pointer to file spec.
; BX - Count of bytes in file spec.
;
; Exit:
; SI - Pointer to file part of file spec.
; BX - Count of bytes of file part in file spec.
;
; Alters: si, bx
;
;**************************************************************************
DbPub pFilePart
cProc pFilePart,<NEAR>,<AX,CX,DX,DI,ES>
cBegin
push ds
pop es
mov di,si
mov al,'\'
mov cx,bx
ScanForBackSlash:
repne scasb
jne NoMoreBackSlash
inc si ; Point after the '\'
mov bx,cx ; Save away the count and the pointer
mov si,di
jmp SHORT ScanForBackSlash
NoMoreBackSlash:
cmp bx,2
jbe pFilePartEnd
cmp byte ptr [si+2],':' ; Is there a drive specification.
jne pFilePartEnd
inc si ; Throw away drive specification.
inc si
dec bx
dec bx
pFilePartEnd:
cEnd
;************************************************************************
; boolean ContContext()
; Purpose:
; Make the current MRS and PRS the one where BASIC's program counter
; is pointing. If CONTinue is not possible, make main module active.
;
; Exit:
; If unable to CONT and no main module
; returns FALSE
; else
; returns TRUE after setting up grs.oRsCur, grs.otxCur
;
;************************************************************************
cProc ContContext,<PUBLIC,NEAR>
cBegin
mov ax,[grs.GRS_otxCONT]
mov [grs.GRS_otxCur],ax
inc ax ;test for UNDEFINED
mov ax,[grs.GRS_oRsCONT]
jne CanCont
;we can't continue, use 'main' module if there is one
mov ax,[grs.GRS_oMrsMain]
inc ax
je CcExit ;brif no main module
mov [grs.GRS_otxCur],0 ;grs.otxCur = 0
dec ax
;ax = oRs containing next stmt to be executed
CanCont:
cCall UiRsActivate,<ax>
mov ax,sp ;return TRUE
CcExit:
or ax,ax ;set condition codes for caller
cEnd
;************************************************************************
; boolean NeedContContext()
; Purpose:
; Make the current MRS and PRS the one where BASIC's program counter
; is pointing. If CONTinue is not possible, make main module active.
;
; Exit:
; If unable to CONT and no main module
; [uierr] = MSG_NoMainProg
; txtErr.oRs = UNDEFINED (so cursor won't be positioned by ReportError)
; returns FALSE
; else
; returns TRUE after setting up grs.oRsCur, grs.otxCur
;
;************************************************************************
cProc NeedContContext,<PUBLIC,NEAR>
cBegin
call ContContext ;activate CONT program counter
jne CcNoErr ;brif can CONT
PUSHI ax,MSG_NoMainProg
call SetUiErr
xor ax,ax ; set ax and condition codes
CcNoErr:
cEnd
sEnd CP
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -