📄 txtmgr.asm
字号:
; a new defining ref otw set to 0
mov [uprs.UPRS_fPrsDelFound],dx ;set fPrsDelFound to 0 if we
; are searching for a defining ref
mov dx,[grs.GRS_oPrsCur] ;set up global specifying which proc
mov [uprs.UPRS_oPrsDel],dx ; we are searching for references to
push cx ;preserve condition flag
;Note that we search even text mrs's because the reference
;to the prs may be within an INCLUDE mrs. It is tempting to
;make INCLUDE mrs's be FM2_NoPcode mrs's, but doing so would
;prevent the ability to select the 'View/Include File' menu
;item when an INCLUDE mrs is active, because the $INCLUDE
;lines would not have been parsed.
;This leads to the situation that an INCLUDE mrs can be
;the owner of a prs. This keeps the prs from being deleted until
;all references to the prs are gone. However, we must also insure
;that the include mrs does not become an owner of a prs when other
;"stronger" definitions exist. Therefore, all prs references from
;an include mrs will be treated as the "weakest" possible owners.
mov bx,CPOFFSET TryToDefPrs
mov al,FE_PcodeMrs+FE_TextMrs+FE_CallMrs+FE_PcodePrs+FE_SaveRs
call ForEachCP
cmp [uprs.UPRS_fNoRefSameMod],FALSE
je GotRefInSameModule ;brif another ref in module found
;We have not found another reference to the Prs in the module from which
;the ref was deleted. Clear the NMSP_sub name table bit of the sub's oNam
;in that module so that it can be used now as a variable name.
push [grs.GRS_oRsCur] ;save current oRs for reactivation
push [uprs.UPRS_oMrsRefDel]
call MrsActivateCP ;activate the module
cCall FieldsOfPrs,<si> ;ax = oNam of proc
xchg bx,ax ;pass bx = oNam of proc
mov al,NMSP_SUB ;pass al = flag to clear
call ResetONamMask ;clear sub bit of oNam of Mrs
call RsActivateCP ;reactivate the Rs we were searching
GotRefInSameModule:
pop cx ;cx = 0 iff otxDef is defined
jcxz J1_FreeAllUndef_Cont ;brif otxDef is defined - i.e. we
; were only searching for another
; ref in module of deletion
cmp [uprs.UPRS_fPrsDelFound],0 ;was a new defining reference found
je ChkDeletePrs ;brif didn't find new "defining" ref
;found new "defining" reference
call SetPrsDefn ;parms are in static struct dprs
J1_FreeAllUndef_Cont:
jmp FreeAllUndef_Cont ;[37] go on to next prs
ChkDeletePrs:
;Prs has no "defining" reference
;If prs has no text table, release it via PrsFree
; By the time this function has been called by PrsDiscard,
; any text table that this prs might have owned will have
; been released.
test [txdCur.TXD_flags],FTX_mrs ;does this prs have a text table?
je J1_FreeAllUndef_Cont ; brif so, will eventually be freed
; by PrsDiscard
call PrsFree ;free the prs
DbAssertRel [grs.GRS_oPrsCur],z,UNDEFINED,CP,<FreeAllUndefinedPrs err>
jmp FreeAllUndef_Cont2 ;[37] go on to look for next prs,
; starting from last prs that
; we did not free ...
FreeAllUndef_Exit:
pop di
pop si
and WORD PTR[flagsTm],NOT(FTM_PrsDefDeleted+FTM2_PrsRefDeleted*100h)
;all Prs entries are clean
ret
FreeAllUndefinedPrs ENDP
;**************************************************************
; UndefPrs(ax:oPrsDelete)
; Purpose:
; This function is called whenever the "defining"
; text reference to a prs is deleted. It clears
; the prs definition flags and sets prs.otxDef to
; undefined.
;
; NOTE: The caller is responsible for calling ChkAllUndefPrs
; to search for a new defining reference, or release
; the prs entry if no more references to the prs exist.
; NOTE: Some callers expect no heap movement from this routine.
;
; Entry:
; ax is the oPrs whose reference is being deleted
;
; Exit:
; prs.otxDef = UNDEFINED
; prs definition flags are cleared.
; restores caller's active register set.
;
;**************************************************************
PUBLIC UndefPrs
UndefPrs PROC NEAR
push [grs.GRS_oRsCur] ;save caller's active register set
push ax ;pass to PrsActivateCP
call PrsActivateCP ;activate prs which may be freed
or [flagsTm],FTM_PrsDefDeleted ;we have deleted a defining reference
mov [prsCur.PRS_otxDef],UNDEFINED ;remember that current "defining"
;reference has been deleted
Msk EQU NOT (FP_DEFINED OR FP_DECLARED OR FP_CDECL)
and [prsCur.PRS_flags],Msk ;turn off these flag bits
;SetPrsDefn will be called to turn
;one or more back on if another ref
;is found in the pcode
call RsActivateCP ;activate caller's register set
; oRs parm is already on stack
ret
UndefPrs ENDP
;**************************************************************
; boolean UpdatePrs()
; Purpose:
; This is called after text has been inserted into, or deleted
; from any text table. It is called for each prs which could be
; declared in this text table (even if by CALL <compiled sub>),
; If the prs's "defining" reference is in this text table:
; If the reference was deleted by the edit:
; Set its Otx field to UNDEFINED
; a new defining reference will be searched for at completion
; of the current edit operation
; else if the "defining" reference was moved by the edit:
; its otx field is updated
; This function will flag many prs entries if the
; deleted text included many DECLAREs, where the DECLARE was the
; only remaining reference.
;
; NOTE: to drastically improve text edit performance, this routine
; gets called by ForEachPrsInPlaceCP, which marches through the
; prs table without activating the PRS. Thus, this routine MUST
; NOT cause heap movement which would invalidate the pointer
; used to march the prs table.
;
; Entry:
; si = ptr to prs entry being examined
; uprs.UPRS_oRsEdit = text table in which edit occurred
; uprs.UPRS_otxEdit = text offset where text was inserted/deleted
; uprs.UPRS_cbDel = number of bytes deleted
; uprs.UPRS_cbIns = number of bytes inserted
;
;**************************************************************
DbPub UpdatePrs
UpdatePrs PROC NEAR
GETRS_SEG es,dx,<SIZE,LOAD> ;[11]
mov dx,PTRRS[si.PRS_otxDef] ; dx = text offset to prs's "defining"
; reference
inc dx ;test for UNDEFINED
je UpExit ;brif prs has no references
dec dx ;restore dx = otxDef
mov ax,PTRRS[si.PRS_oRsDef]
cmp BPTRRS[si.PRS_procType],PT_DEFFN
jne UpdNotDefFn ;brif not a DEF FN
mov ax,PTRRS[si.PRS_oMrs] ; DEF FNs live in a module's text table
UpdNotDefFn:
cmp ax,[uprs.UPRS_oRsEdit]
jne UpExit ;brif not text table being edited
;prs is currently defined by reference in edited text table
mov ax,[uprs.UPRS_otxEdit]
cmp dx,ax
jb UpExit ;brif reference unaffected by edit
add ax,[uprs.UPRS_cbDel]
cmp ax,dx
jbe UpMoved ;brif defining ref moved by edit
;Defining reference has been deleted.
;Mark Prs to indicate that defining reference has been deleted.
mov ax,si ;ax = ptr to prs entry
RS_BASE sub,ax ;ax=oPrs for entry, parm to UndefPrs
call UndefPrs ;Mark Prs as "defining" reference as
;deleted
jmp SHORT UpExit
;defining reference has been moved up or down in memory
UpMoved:
mov ax,[uprs.UPRS_cbIns]
sub ax,[uprs.UPRS_cbDel]
add PTRRS[si.PRS_otxDef],ax ; update otx based on edit
UpExit:
or ax,sp ; return ax != 0 and NZ
ret
UpdatePrs ENDP
;**************************************************************
; boolean NEAR TxtDelete(otxDelFirst, otxDelLast)
; Purpose:
; Delete some text from the current text table.
; Doesn't update linked lists if ASCII load is active.
;
; NOTE:
; If a Prs's "defining" reference is being deleted, this function
; will cause the prs to be marked as UNDEFINED. It is up to
; the caller to insure that orphaned "New" defining references
; the prs do not exist by calling ChkAllUndefPrs if the possibility
; of deleting a "defining" reference has occurred during the
; edit operation.
;
; Entry:
; Same as for TxtChange:
;
; Exit:
; Same as for TxtChange
; [cForDel] = 1 + number of FOR statements deleted
; [cForStepDel] = 1 + number of FOR...STEP statements deleted
; Condition codes are set based on value in ax
;
;**************************************************************
cProc TxtDelete,<PUBLIC,NEAR,NODATA>,<si,di>
parmW otxDelFirst
parmW otxDelLast
localW otxNext
localW otxTop
localW otxBottom
localW oTyp
localW cbDel
cBegin
DbAssertRelB [txdCur.TXD_scanState],ne,SS_EXECUTE,CP,<TxtDelete err 1>
DbChk Otx,otxDelFirst ;error if > txdCur.bdlText.cbLogical
DbChk Otx,otxDelLast ;error if > txdCur.bdlText.cbLogical
DbAssertRel [otxDelFirst],be,[otxDelLast],CP,<TxtDelete err 2>
mov di,[otxDelFirst]
mov al,[bigEditState]
cmp al,BIG_EDIT_CANCEL
jne DelNoCancel
jmp DelGoodExit ;backout of BigEdit if user CANCELed
DelNoCancel:
cmp [txdCur.TXD_SCANSTATE],SS_SUBRUDE
jne DelNotSubRude ;
jmp DelNoThreads ;don't need to examine text before
; deletion if no oPrs's in code
DelNotSubRude: ;
cmp al,BIG_EDIT_FALSE
jne DelInBigEdit ;brif in a BigEdit
mov [cForDel],1
mov [cForStepDel],1
DelInBigEdit:
;-------------------------------------------------------------------
;Examine the block of pcode being deleted opcode by
;opcode, looking for a RUDE EDIT
;
mov cx,[otxDelLast]
sub cx,di ;compute cb to be deleted
mov [cbDel],cx
jcxz DelPreDone ;brif no text to delete, destroy scrap
test [mrsCur.MRS_flags2],FM2_Include OR FM2_NoPcode
jne DelNotTextMrs ;brif document/include file is active
cmp [b$cNonQBIFrames],0 ;nonzero when non-QBI frames are on
; the stack. Any edit at this point
; could invalidate return addresses on
; the stack. At this point we have
; decided to askcantcont instead of
; trying to fix up the return addresses
; on the stack.
;are non qbi return addresses on stack?
jne DelAskCantCont ;brif so, check for possible back out
DelNotTextMrs:
test [mrsCur.MRS_flags2],FM2_Include
je DelNotIncl1 ;brif not editing an include file
DelAskCantCont:
call AskCantCont_CP ;ask user "Want to back out?"
je J1_DelBackOut ;return FALSE if user wants to back out
DelNotIncl1:
push di ;pass [otxDelFirst]
PUSHI ax,<CODEOFFSET tOpPreDel>
call TxtFindOp ;find 1st opcode of interest
;ax = offset to 1st opcode of interest
;dl = [txtFindIndex]
DelPreLoop:
cmp ax,[otxDelLast]
jae DelPreDone ;brif no significant opcodes were in
;deleted range
xchg si,ax ;si = text offset to current opcode
;opBol and opBolLab are in the PREDEL list to keep us from unnecessarily
; searching all the way to opEot for innocuous edits of large "simple"
; txt tables. This can significantly speed up simple edits.
cmp dl,PREDEL_BolMax ;is this just a Bol?
jbe J1_DelPreNext ;brif so, search for next opcode.
cmp dl,PREDEL_IncludeMax
jbe DelInclude ;brif INCLUDE (or $INCLUDE [QB4])
;It must be PREDEL_rudeMin or greater - rude edit
push dx ;save txtfindindex in case AskRudeEdit
;calls TxtFind
call AskRudeEdit ;see if user wants to back out of edit
pop ax ;al = txtfindindex
je J1_DelBackOut ;return FALSE if user wants to
; back out of edit
FloadActive ;don't descan if Loading
jne DelPreNext
cmp al,PREDEL_opStDefType
jne DelPreNext ;brif not DEFINT..DEFSTR stmt
call SystemDescanCP ;implicit parms in DECLARE, SUB,
; FUNCTION stmts need to be rechecked
; by the scanner
DelPreNext:
push si
PUSHI ax,<CODEOFFSET tOpPreDel>
call TxtFindNextOp ;find next opcode of interest
jmp SHORT DelPreLoop
DelInclude:
push si ;pass otx
call OtxNoInclude ;ax = otx to opBol/opEot for next line
; which has no $INCLUDE
cmp ax,[otxDelLast] ;is end of $INCLUDE pcode beyond
; requested delete?
jbe J1_DelPreNext ;brif not
mov [otxDelLast],ax ;delete all included lines as well
sub ax,di ;ax = new cbDel
mov [cbDel],ax
J1_DelPreNext:
jmp SHORT DelPreNext
J1_DelBackOut:
jmp DelBackOut ;return FALSE - user wants to
; back out of edit
;-------------------------------------------------------------------
; If fFillScrap and bdTxtScrap is empty,
; fFillScrap = FALSE
; copy deleted text to bdTxtScrap
; otxScrap = otxDelFirst
; If cbBigIns > 0, cbBigIns -= cbDel
;
;Note that cbDel may actually be zero but that we still create the scrap
;because we may subsequently be called during a big edit with fFillScrap
;TRUE but we don't want to fill the scrap.
DelPreDone:
cmp [fFillScrap],FALSE
je DelNoCopy ;brif no need to copy text to scrap
cmp [bdlTxtScrap.BDL_status],NOT_OWNER
jne DelNoCopy ;brif scrap is already in use
mov [fFillScrap],FALSE ;reset one-shot flip-flop
mov [otxScrap],di ;remember text offset of deleted text
; CALL TxtCopyScrap(otxDelFirst, 0, cbDel, FALSE) [9]
push di ;push otxDelFirst
xor ax,ax
push ax ;offset of where to copy into Scrap
push [cbDel]
push ax ;push FALSE meaning don't delete text
call TxtCopyScrap ;ax = 0 if out of memory
jnz CopiedOK ;brif buffer allocated successfully
call AskRudeEdit ;Give user a chance to back out of edit
; if CONT is currently possible.
je J1_DelBackOut ;return FALSE if user wants to
; back out of edit
jmp SHORT DelNoCopy
CopiedOK:
;-------------------------------------------------------------------
;NOTE: At this point, the user CANNOT back out of the edit.
; All actions from this point on are irreversible.
;
;Examine the block of pcode being deleted opcode by
;opcode, taking special action for each opcode of interest.
;
; Register usage for loop: si = otxCur, di = otxDelFirst
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -