⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uimain.asm

📁 Dos6.0
💻 ASM
📖 第 1 页 / 共 3 页
字号:
	TITLE	uimain.asm - BASIC's top level interface to user interface.
;***
;uimain.asm
;
;	Copyright <C> 1985-1988, Microsoft Corporation
;
;Purpose:
;	Main user interface, and support routines.
;
;
;*******************************************************************************

	include	version.inc

	UIMAIN_ASM = ON

	;Next, include COW's interface headers
	include cw/version.inc
	include cw/windows.inc
	include cw/edityp.inc

	;Next, include QBI's headers
	includeOnce	architec
	includeOnce	context
	includeOnce	executor
	includeOnce	heap
	includeOnce	parser
	includeOnce	qbimsgs
	includeOnce	rtinterp
	includeOnce	txtmgr
	includeOnce	ui
	includeOnce	uiint
	includeOnce	uimenu	

assumes	ds,DATA
assumes	ss,DATA
assumes	es,NOTHING

	; external procedures used by uictl	
						
	externFP EnableMenuItem 		
	externFP CheckMenuItem			
	externNP fCanContUI			
	externNP GetEditLine			
	externFP SetBlinkBit
IFNDEF ROMBASIC
        externFP FCheckTandy1000
ENDIF

	;Runtime supplied functions used by this module:
	
	EXTRN	B$UnhookKbd:FAR
	EXTRN	B$hookKbd:FAR


sBegin	DATA

	externW fIsProgram 		
	externB fPasteOK		
	externB fSyntaxCheck		
	externW cWatch			
	externB fInsertMode		;EditMgr insert state.

	EXTRN	b$fCompErr:word	;non-zero if error was in compiled code
	EXTRN	fRefreshWatch:byte	;non-zero if WATCH window needs to
					; be refreshed

	externW	szDialogTitle		; * current dialog box title, or
					; 0 if no title.
;fUiActive is TRUE when user-interface keyboard and mouse interrupt
;handlers are active.
PUBLIC  fUiActive
fUiActive	dw	0
fUIInit 	db	0		; non-zero if UI Initialized.

;When we can CONTinue, and we execute a direct mode stmt that causes a ret
; adr to the direct mode buffer to be pushed on the stack (call/gosub/func),
; and then enter direct mode to save the otx of the called routine, we save the
; old grs.otxCont in otxContProg, so that after the direct mode call finishes,
; we can still CONTinue the stopped program.
;This variable gets set to UNDEFINED if we do any EDITs (because otxContProg
; isn't updated as pcode is moved by the text mgr and static-scanner).
;It is also set to UNDEFINED if we execute another direct mode stmt
; while there is a return address to the direct mode buffer on the stack,
; because we choose not to remember an arbitrary number of these, and
; it would be difficult for the user to keep track of them anyway.
;TxtDirect guarentees that if user enters a direct mode statement
; while there is a return address to the direct-mode-buffer on the
; stack (FG_RetDir), that CantCont will occur.
;
otxContProg	DW UNDEFINED

cGrab	db	0		;number of active callers of UiGrabSpace
sEnd	DATA

sBegin	UI
assumes cs,UI


;**************************************************************************
; UiInit
; Purpose:
;	In QB, the RUNTIME gets control first (since in stand-alone EXEs
;	there is no user-interface).  This is called after the runtime
;	has initialized.  It initializes the user interface.
; Entry:
;	cmdSwitches has flags set to indicate command-line switch settings
; Exit:
;	the file QB.INI is read
;	If command line didn't contain /RUN <filename>, the debug screen
;	   is shown.
;	AX nonzero if Out of Memory
;	
;**************************************************************************
cProc	UiInit,<PUBLIC,FAR>
cBegin
; Set colors at beginning so first screen writes are the same color.
	call	ReadQbIni
	call	B$UnhookKbd
IFNDEF ROMBASIC
        call    FCheckTandy1000         ;check for/install TANDY 1000 KBD
ENDIF
	call	CwInit
	call	B$HookKbd
	test	[cmdSwitches],CMD_SW_RUN ;/RUN filename given on command line?
	jnz	NoDebugScr		;  brif so, no debug screen
	call	EnsShowDebugScr
NoDebugScr:
	call	GrabSpace		;make sure we can successfully
	or	ax,ax			;  GrabSpace (ax = 0 if failed)
	not	ax			;0 -> -1 if failed, preserves flags
	jz	UiInitExit		;brif failure, exit with ax<>0
	call	ReleaseSpace		;release what we grabbed
	xor	ax,ax			;exit with ax = 0 for success
UiInitExit:				
	inc	fUIInit 		;indicate UiInit complete
cEnd

;**************************************************************************
; UiTerm
; Purpose:
;    Called just before we are about to leave the QB for good.
;    Calls COW and KKIF to tell it to terminate.
;
;    Also called before a SHELL is performed.  The runtime calls
;    this routine prior to SHELL, or at termination.  After a SHELL,
;    The runtime calls UiReInit so COW can re-initialize.
; Entry:
; Exit:
;	
;**************************************************************************
cProc	UiTerm,<PUBLIC,FAR>
cBegin
	cmp	fUIInit,0	; were we ever initialized?
	jz	UTExit		; brif not, exit now

	cCall	WriteQbIni	; write the qb.ini file
	cCall	CwTerm		
	mov	al, 1			
	cCall	SetBlinkBit,<ax>
UTExit:
cEnd

;**************************************************************************
; UiReInit
; Purpose:
;	In QB, the RUNTIME needs to reinitialize the user interface
;	at certain points (primarily after SHELL).  This entry point
;	allows the user interface to reestablish any state (such as
;	hooking interrupts) that is necessary.
; Entry:
;	none.
; Exit:
;	none.
;	
;**************************************************************************
cProc	UiReInit,<PUBLIC,FAR>
cBegin
cEnd

;**************************************************************************
; UiPause
; Purpose:
;    Added with [24].
;    Called before a SHELL is performed.  The runtime calls
;    this routine prior to SHELL, or at termination.  After a SHELL,
;    The runtime calls UiReInit so COW can re-initialize.
; Entry:
; Exit:
;	
;**************************************************************************
cProc	UiPause,<PUBLIC,FAR>
cBegin
cEnd

;**************************************************************************
; UserInterface()
; Purpose:
;  UserInterface() is the primary interface the user-interface
;  provides to the rest of BASIC.
;  It is called by the beginning-of-statement/line
;  executor when it sees bosMask & BOS_DEBUG non-zero,
;  by opEot and opStEnd (end-of-program), opBreakPoint, and opStStop.
;
;  For example, if tracing was active for the program:
;    CLS : PRINT
;    STOP
;  UserInterface would be invoked between the opcodes seperated by '^':
;    opBol ^ opStCls opBos ^ opBreakPoint ^ opStPrint opBol ^ opStStop ^ opEot ^
;
; Entry:
;  grs.oRsCur, otxCur identify the next statement to be executed.
;  If grs.otxCur == UNDEFINED, it means we've just executed an ExEot,
;     and thus cannot continue.  Otherwise, it points just beyond the
;     ExBos opcode which caused UserInterface to be called.
;  If the parser's input buffer (ps.bdpSrc) contains any text, that
;     text is executed as if the user entered it as a direct mode stmt.
;     This allows executors like RUN <filename> to load the file, then
;     re-invoke UserInterface after stuffing the command "RUN" in the
;     parser's input buffer.  This allows there to be only 1 control path
;     to scan all loaded text tables.
;
;  The actions performed by UserInterface() are determined by which
;  bits are set in debugFlags as follows:
;
;  DEBUG_EXEC_CMD - set by some executor like RUN <file>/CHAIN <file>,
;     which has loaded pcode, and now wants the pcode to be scanned
;     and a direct mode statement executed (like RUN or CONT).  The
;     executor for the direct mode stmt has been loaded into grs.bdlDirect.
;
;  DEBUG_ERROR - set when a runtime error occurs and
;     is not trapped.  The runtime error code restores SI to
;     the beginning of statement, sets this flag, then re-
;     executes the statement, which invokes the debugger.
;     The error code is passed in the same static variable
;     examined by the ERR intrinsic function.  Causes
;     DebugError() to be invoked.
;
;  DEBUG_STOP - set when a STOP statement is executed,
;     when Ctrl-BREAK is pressed and not trapped, or
;     when a breakpoint is executed.
;     Causes DebugStop() to be invoked.
;
;  DEBUG_WATCHPOINT - set when a Stop-Watch-Expression evaluates to TRUE
;     Causes DebugStop() to be invoked.
;
;  DEBUG_END - set by the executors for opEot and
;     opStEnd to indicate end-of-program.  Causes DebugEnd()
;     to be invoked.
;
;  DEBUG_TRACE - set while tracing statement execution
;     either because of TRON, single-step, or procedure-
;     step.  Causes DebugTrace() to be invoked.
;
;  DEBUG_WATCH - set when any Watch Expressions are
;     active in the program.  Causes DebugWatch() to be invoked.
;
;  DEBUG_CANT_CONT - Causes UserInterface() to set grs.otxCONT to
;     UNDEFINED the next time it is called.
;     This is used by executors, which cannot call CantCont
;     because UserInterface sets grs.otxCONT every time
;     we enter UserInterface, thus undoing their change.
;     Since it sets otxCONT rather than calling CantCont(),
;     stack tracing and variable printing are still possible
;     from direct mode, just not continuing.
;
; Exit:
;	grs.fDirect, grs.oRsCur, grs.otxCur indicate where pcode
;	   execution is to commence
;
;**************************************************************************
cProc	UserInterface,<PUBLIC,FAR>
cBegin
	DbAssertRelB [cGrab],e,0,UI,<UserInterface: cGrab non-zero>
	test	[debugFlags],DEBUG_WATCH
	je	NoWatch			;brif no WATCH expressions visible
	call	DebugWatch		;get next watch expression, or
					; normal program pcode
	jne	J1_TestRestore		;brif the next pcode to be executed
					; is WATCH pcode, DebugWatch has
					; set grs up so it's ready to go
	cmp	[fDebugScr],FALSE
	jne	NoWatch			;brif debug screen is visible
					; need to print values in watch window
	test	[debugFlags],NOT DEBUG_WATCH
	jne	NoWatch			;brif WATCH isn't only thing to do
					;speeds up WATCHPOINTs significantly
J1_TestRestore:
	jmp	SHORT TestRestore
	;If we didn't care about Watch functions that write to the screen
	; we could branch to ExecStmt and be faster, but since most watchpoints
	; are handled by the executor calling DebugWatch directly, the only
	; watch points we are slowing down are when the debug screen is active.

NoWatch:
	cmp	[grs.GRS_fDirect],FALSE
	je	NotInDirect		;brif not executing direct mode stmts

	;Following test prevents tracing statements in direct mode.
	test	[debugFlags],NOT (DEBUG_TRACE OR DEBUG_WATCH)
	je	GotNextStmt		;brif nothing other than TRACE/WATCH

	;We've returned to direct mode, potentially after having debugged
	;a GOSUB/SUB/FUNCTION/DEF FN.  If we don't set otxCur to
	;otxContProg, we'd show the RETURN or END DEF/SUB/FUNCTION
	;stmt as the next stmt to be executed, instead of the statement
	;that was active before the direct mode statement executed.
	
	mov	ax,[otxContProg]
	mov	[grs.GRS_otxCur],ax	;will be stored in grs.otxCONT

NotInDirect:
	;we were not executing in direct mode, setup for CONT executor.
	;If grs.otxCur == UNDEFINED (as set by opEot), we cannot continue
	
	cmp	[debugFlags],0
	je	GotNextStmt		;brif nothing to do.  This is true
					;for the 1st non-direct-mode-buffer
					;pcode we execute.  Once we branch
					;out of the direct mode buffer,
					;there's no need to call UserInterface
					;between statements.
	mov	ax,[grs.GRS_oRsCur]
	mov	[grs.GRS_oRsCONT],ax
	test	[txdCur.TXD_flags],FTX_mrs
	je	NotInDefFn		;brif definately not within a DEF FN
	mov	ax,[grs.GRS_oMrsCur]
NotInDefFn:
	mov	[grs.GRS_oRsContTxtTbl],ax

	mov	ax,[grs.GRS_otxCur]
	mov	[grs.GRS_otxCONT],ax
GetNextStmt:
	;Call NextStmt() to determine what stmt should be executed next.
	;NextStmt() may interact with user, letting user edit program etc.
	
	call	NextStmt

	;If user added or removed a WATCH expression, we need to refresh
	;the values in the Watch window.
	
	cmp	[fRefreshWatch],FALSE
	je	GotNextStmt
	mov	[fRefreshWatch],FALSE
	call	DebugWatch
	je	GetNextStmt		;brif can't execute WATCH pcode
					; for any reason
GotNextStmt:
	cmp	[cWatch],0
	je	TestRestore		;brif no WATCH expressions are active
	or	[debugFlags],DEBUG_WATCH; tell Executor to call UserInterface
					; after executing next statement

;The reason we enter direct mode for each statement, regardless of
;the state of debugFlags, is so we can toggle to the output screen
;for direct mode lines like:
;    FOR I=1 TO 10: PRINT A(I): NEXT I
;but leave the debug screen active for direct mode lines like:
;    FOR I=1 TO 10: A(I) = 1: NEXT I
;
;Make the output screen visible IF:
; we're tracing or watching variables AND next stmt does screen I/O OR
; we're NOT tracing or watching variables AND next stmt is in program
;   (as opposed to direct mode statement buffer)
;
TestRestore:
	cmp	[fDebugScr],FALSE
	je	ExecStmt		;brif output screen already visible
					;If this test is removed, callers
					;who set DebugFlags.DEBUG_EXEC_CMD
					;need to put an ExEot in bdlDirect
					;for FNextStmtDoesIO
	test	[debugFlags],DEBUG_WATCH OR DEBUG_TRACE
	jne	TestForIO		;brif we're watching or tracing
	cmp	[grs.GRS_fDirect],FALSE
	je	ShowUserScr		;brif not executing direct mode stmts
TestForIO:
	call	FNextStmtDoesIO
	or	ax,ax
	je	ExecStmt		;brif next stmt causes no screen I/O
ShowUserScr:
	call	EnsShowOutSaveRs	;show output screen, don't alter
					; grs.oRsCur

ExecStmt:


;***** Begin revision [17]
	
	;Clear FBOSSTOP in bosFlags now, because we have just had the
	;chance to responde to it so if it is still set it is because
	;we stopped for some other reason.  There for, the FBOSSTOP
	;has already been serviced.
	
	and	[bosFlags], NOT FBOSSTOP
;***** End revision [17]

	;If we are debugging or we are executing a direct mode statement,
	;make sure we re-enter user interface for each opBos.
	
	mov	al,[debugFlags]

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -