📄 uimain.asm
字号:
or al,[grs.GRS_fDirect]
je DontReEnter
or [bosFlags],FBOSDEBUG ;tell executor to call UserInterface
; at the next beginning of stmt
DontReEnter:
;ContReinitStat needs to be called every time we exit the
;user interface if any editing/loading took place. It ensures
;there is no unused space within BDs and no free space between
;near-heap entries. If there was any, a string allocation could fail
;even though there is free space, because arrays of string descriptors
;can only be moved at statement level, because the runtime
;could have several pointers to them, i.e. x$=a$(1)+a$(2)
call ContReinitStat
;Return to the executor to execute pcode indicated by:
;grs.fDirect, grs.oRs, grs.otx.
;If the Quit menu item is selected, or the SYSTEM command is entered
;UserInterface returns to let the executor execute ExStSystem.
;Returning from this function causes the pcode-executor to begin.
;
cEnd ;UserInterface
;**************************************************************************
; EnterUserInterface()
; Purpose:
; Enable all user interface interrupt handlers.
;
;**************************************************************************
cProc EnterUserInterface,<PUBLIC,NEAR>
cBegin
cmp [fUiActive],0
jne EntDmExit ;brif already in user interface
mov [fUiActive],sp
KbLoadOk:
cCall DrawDebugScr
cCall B$UnhookKbd ;tell runtime to disable its handler
cCall HookInt24 ;enable interrupt-24 interrupt handler
cCall CwHook
call FlushMsgs ;flush any type-ahead keystrokes or
; mouse clicks
EntDmExit:
;Set the BIOS INSERT flag to match what we will be using in
;this invocation of the UI. This will keep us in ssync with
;what speach software thinks our insert state is.
xor bx, bx
mov es, bx
cli ; don't allow interrupts (might
; change BIOS flags on us)
mov al, es:[417h] ; get BIOS shift state flags
and al, 7fh ; assume insert mode off
cmp fInsertMode, bl ; is CW in an insert mode
je @F ; brif not, assumption good
or al, 80h ; set BIOS insert mode on
@@:
mov es:[417h], al ; update BIOS flags
sti ; reenable interrupts
cEnd ;EnterUserInterface
;**************************************************************************
; ExitUserInterface()
; Purpose:
; Unhooks all user interface interrupt handlers.
;
;**************************************************************************
cProc ExitUserInterface,<PUBLIC,NEAR>
cBegin
call FlushMsgs ;flush any type-ahead keystrokes or
; mouse clicks
DbAssertRel [fUiActive],ne,0,UI,<ExitUserInterface: not in user interface>
mov [fUiActive],0
cCall CwUnHook
cCall UnHookInt24
cCall B$hookKbd ;tell runtime to enable its handler
cEnd ;ExitUserInterface
;**************************************************************************
; DebugExecCmd
; Purpose:
; Invoked when we enter NextStmt with DEBUG_EXEC_CMD bit set in
; debugFlags
; Exit:
; Returns actionFlag bit which will cause the work to get done.
;
;**************************************************************************
DebugExecCmd PROC NEAR
mov [grs.GRS_otxCONT],UNDEFINED
;RUN <filename> needs otxCont UNDEFINED
; so scanner can grow variable tables.
mov al,FDM_ExecCmd
ret
DebugExecCmd ENDP
;**************************************************************************
; NextStmt
; Purpose:
; Called by UserInterface() to determine the next opcode to be executed
; It is only called when UserInterface has something significant to do.
;
; Entry:
; same as for UserInterface()
;
;**************************************************************************
.errnz DEBUG_ERROR - 01h
.errnz DEBUG_EXEC_CMD - 02h
.errnz DEBUG_STOP - 04h
.errnz DEBUG_END - 08h
.errnz DEBUG_WATCHPOINT - 10h
.errnz DEBUG_TRACE - 20h
DebugDispTbl LABEL WORD
DW UIOFFSET DebugError
DW UIOFFSET DebugExecCmd
DW UIOFFSET DebugStop
DW UIOFFSET DebugEnd
DW UIOFFSET DebugStop
DW UIOFFSET DebugTrace
DebugDispTblEnd LABEL WORD
DbPub NextStmt
cProc NextStmt,<NEAR>
localB actionFlags
localB debugFlagsTmp
cBegin
DbAssertRelB [cGrab],e,0,UI,<NextStmt: cGrab non-zero>
;remember if the debug screen was visible when we entered NextStmt()
mov al,[debugFlags]
mov [debugFlagsTmp],al
test al,DEBUG_ERROR
jne GotRtErr
;Set b$fCompErr 0 so any errors generated from within the user
; interface don't look like they were generated in QuickLibrary.
mov [b$fCompErr],0
GotRtErr:
;reset any variables that assume we're in same context we were
;in last time they were set.
call UiFlushCache
sub ax,ax
mov [actionFlags],al
mov [debugFlags],al
mov [fDoCmd],ax
; Dispatch to function based on debugFlagsTmp. Function
; returns ushort mask with 0 or more of FDM_xxx bits set
; indicating what action is to be performed.
; Function also sets various bits in debugFlagsTmp to cause
; UserInterface to be entered after the next statement is executed.
;
; NOTE: The order these flags are tested is IMPORTANT
;
mov al,[debugFlagsTmp]
and al,DEBUG_EXEC_CMD+DEBUG_ERROR+DEBUG_STOP+DEBUG_END+DEBUG_WATCHPOINT+DEBUG_TRACE
je DispRet ;brif nothing interesting
mov bx,UIOFFSET DebugDispTbl-2
DispLoop:
inc bx ;advance to next exception handler
inc bx
DbAssertRel bx,b,<UIOFFSET DebugDispTblEnd>,UI,<uimain.asm: Bad debugFlags>
shr al,1
jnc DispLoop
call cs:[bx] ;dispatch to routine based on debugFlags
;al = bit mask of actions to carry out
DispRet:
mov [actionFlags],al
test al,FDM_ShowStmt
je TestGetCmd ;brif cursor not to be positioned
call EnsShowDebugScr ;make debug screen visible
call DoDrawDebugScr ;actually draw debug screen, can't
; wait for next call in GetCmd() in the
; case where user just executed a TRON
; stmt, we don't call GetCmd at all
call ContContext ;activate "program counter's" context
je TestGetCmd ;brif can't continue & no main program
;otx may point to beginning of next statement, get it back to current
;map UNDEFINED,0,1,2,3,... to 0,0,0,1,2,3,...
mov ax,[grs.GRS_otxCONT]
inc ax ;test for UNDEFINED
je DoShowStmt ;if can't CONT, cur stmt is 0 of main
dec ax ;restore ax = otxCONT
je DoShowStmt ;map 0 to 0
dec ax ;map 1,2,... to 0,1,...
DoShowStmt:
push [grs.GRS_oRsCur]
push ax ;pass otxCur
PUSHI ax,UNDEFINED ;determine column from otx
call ShowStmt
TestGetCmd:
;See if executor told user interface to not allow continuing.
;This is done when it wants to show where execution stopped
;(i.e. for error reporting) so it leaves grs.otxCur not UNDEFINED
;on entry to UserInterface. It is important that we not call CantCont
;before calling ShowStmt, or else ShowStmt has nothing to show.
test [debugFlagsTmp],DEBUG_CANT_CONT
je CantContNotSet
call CantCont
mov [actionFlags],FDM_GetCmd
CantContNotSet:
test [actionFlags],FDM_GetCmd
je TestDoCmd
;Init debug screen if necessary, make it visible. This is necessary
;because DEBUG_END causes FDM_GetCmd to be set, but not FDM_ShowStmt.
;Continue calling GetCmd() until we get a command which we can execute
;without errors. GetCmd() interacts with user until user enters a
;direct-mode command (which may take the form of a menu selection, or
;accelerator key like SingleStep).
;This can cause context switches to different module and
;procedure text tables. It also invokes the text
;manager (which invokes the parser) to alter program text.
;
GetCmdLoop:
;Turn off CMD_SW_RUN switch in case user specified /RUN <filename>
;in qb command line, and then got a runtime error. This will
;cause the SYSTEM statement to return to user interface rather than
;terminating qb.
and [cmdSwitches],NOT CMD_SW_RUN
call EnsShowDebugScr
call EnterUserInterface ;enable userInterface interrupt handlers
mov [otxContProg],UNDEFINED ;since this call to GetCmd can cause
; editing, and otxContProg isn't updated
; for pcode movement, we can't depend
; on it after this call.
call GetCmd
call WatchInfoUI ;update cWatch if necessary
WatchWnOk:
call ExitUserInterface ;restore runtime's interrupt handlers
;Make sure TxtDirect and SystemScan are unable to tie up so much
;variable table space that we are unable to execute very simple
;direct mode statements. This block of memory will be freed
;by UiReleaseSpace below. Be very careful when changing control
;flow below this point that all UiGrabSpace calls are balanced by
;UiReleaseSpace calls.
TestDoCmd:
call UiGrabSpace ; UiGrabSpace can take a lot of time...
; slows down tracing, and WATCH (when
; debug screen is visible)
cmp [fDoCmd],0 ; fDoCmd can only be set as a result
; of calling GetCmd(). It is not
; set as a if user wants to TRACE
je NoDirect ; brif all scanned and ready to execute
; (speed optimization for WATCH/TRACE)
mov [fDoCmd],0
call ContContext ;activate "program counter's" context
; for TxtDirect
call TxtDirect ;Now parse & scan direct mode statement
mov ax,[grs.GRS_otxCONT]
mov [otxContProg],ax
jmp SHORT CheckErr
;no direct mode stmt (we're tracing), just scan all text tables
;and set current context to grs.otxCONT
NoDirect:
call SystemScan
test [actionFlags],FDM_ExecCmd
je NoExecCmd
;some executor setup direct mode buffer, i.e. ExRunFile
;loaded program and put ExRunMain in grs.bdlDirect
cmp [txtErr.TXER_errCode],0
jne CheckErr ;dont set otxCONT if scan error
mov ax,[grs.GRS_oMrsMain]
mov [grs.GRS_oRsCONT],ax
push ax
call UiRsActivate ;activate oRs to continue
sub ax,ax
mov [grs.GRS_otxCur],ax
mov [grs.GRS_otxCONT],ax ;ExStChain causes ExStCont to be
; invoked, which needs otxCONT=0
dec ax
mov [grs.GRS_fDirect],al ;execute pcode out of direct mode buf
;If we were tracing when we entered with DEBUG_EXEC_CMD,
; continue tracing. The only reason we entered DirectMode
; was to SystemScan and report errors.
mov al,[debugFlagsTmp]
and al,DEBUG_TRACE
or [debugFlags],al
jmp SHORT CheckErr ;report any parser/scanner errors
NoExecCmd:
call NeedContContext ;activate "program counter's" context
; if no main module, uierr is set
je SHORT GetNextCmd ;brif CONT is not possible
;now see if TxtDirect/SystemScan encountered any errors
CheckErr:
mov ax,[txtErr.TXER_errCode]
or ax,ax
jne CmdErr ;brif parser/scanner errors
;We could get here without having called UiGrabSpace (if we were
;tracing, and all text tables were already scanned to SS_EXECUTE)
;If we didn't call UiGrabSpace, we are guarenteed that cGrab=0
;by assertion at entry of NextStmt().
cmp [cGrab],0
je NoneGrabbed1
call UiReleaseSpace
NoneGrabbed1:
cEnd ;NextStmt
CmdErr:
inc ax ;test for UNDEFINED
je GetNextCmd ;brif user wants to back out of cmd
; because it would prevent CONT
dec ax ;restore ax=errCode
mov [uierr],ax ;remember to report error in GetCmd's
GetNextCmd: ; structure txtErr.xxx
call UiReleaseSpace ;at this point, we know we called
; UiGrabSpace. Release it
jmp GetCmdLoop
;*********************************************************************
; AskCantCont()
;
; Purpose:
; AskCantCont() is called by TextMgr when it is about to make an
; edit which would prevent continuing program execution.
; This function should not be called during exection. It is not
; valid (or useful) while the executor is in operation.
; If already impossible to continue (i.e. grs.otxCONT ==
; UNDEFINED) AskCantCont returns TRUE. Otherwise, the user is warned
; with a dialog box that this edit will prevent continuing.
; If the user says OK, grs.otxCONT is set to UNDEFINED
; and the context manager's CantCont() is called (which
; sets grs.otxCONT to UNDEFINED among other things.
; AskCantCont() then returns TRUE.
; If the user says CANCEL, the Debug screen is refreshed (discarding
; the current edit) and AskCantCont() returns FALSE.
;
; Exit:
; Returns FALSE if user wants to abort current edit, with
; condition codes set based on value in ax.
;
;*********************************************************************
cProc AskCantCont,<PUBLIC,FAR>
cBegin
call fCanContUI
je AcCantCont ;brif already can't continue
;display "This will prevent CONT, proceed anyway?"
PUSHI ax,MB_OKCANCEL
PUSHI ax,MSG_CantCont
call MsgBoxStd
cmp al,IDOK
mov ax,0 ;prepare to return FALSE
jne AcExit ; brif user wants to backout of edit
call CantCont ;disable CONT
AcCantCont:
mov ax,sp ;return TRUE
AcExit:
or ax,ax ;set condition codes for caller
cEnd ;AskCantCont
;*********************************************************************
; AskMakeRem()
; Purpose:
; The user tried to insert a blank line before a SUB/FUNCTION line.
; This would cause us grief when we tried to ASCII save/load the
; file, because blank lines delimit the block of comments that are
; to remain with the SUB/FUNCTION. The case where this is important
; is when the user has a module with no module level code, but still
; wants to have a block of comments at module-level.
; If we allowed blank lines in the block of comments that we move
; into the SUB during ASCII load, this block of module comments
; would be moved as well.
;
; Exit:
; Returns FALSE if user wants to abort current edit, with
; condition codes set based on value in ax.
;
;*********************************************************************
cProc AskMakeRem,<PUBLIC,FAR>
cBegin
;"Blank lines not allowed before SUB/FUNCTION line. Is remark ok?"
PUSHI ax,MB_OKCANCEL
PUSHI ax,MSG_MakeRem
call MsgBoxStd
sub ax,IDCANCEL ;ax=0 if user said CANCEL
cEnd
;*********************************************************************
; NotSaved(), NotSavedInc(), NotSavedIncSav()
;
; Purpose:
; Called by Context Mgr's NewStmt and SYSTEM executor when it is about
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -