txtsave.asm
资源名称:DOS系统的源代码.rar [点击查看]
上传用户:xiaoan1112
上传日期:2013-04-11
资源大小:19621k
文件大小:35k
源码类别:
操作系统开发
开发平台:
Visual C++
- TITLE txtsave.asm - ASCII Save Functions
- ;==========================================================================
- ;
- ;Module: txtsave.asm - ASCII Save Functions
- ;System: Quick BASIC Interpreter
- ;
- ;=========================================================================*/
- include version.inc
- TXTSAVE_ASM = ON
- includeOnce architec
- includeOnce context
- includeOnce heap
- includeOnce lister
- includeOnce names
- includeOnce opcontrl
- includeOnce opid
- includeOnce opmin
- includeOnce opstmt
- includeOnce parser
- includeOnce pcode
- includeOnce qbimsgs
- includeOnce rtinterp
- includeOnce rtps
- includeOnce rttemp
- includeOnce scanner
- includeOnce txtmgr
- includeOnce txtint
- includeOnce util
- includeOnce ui
- includeOnce variable
- includeOnce edit
- assumes DS,DATA
- assumes SS,DATA
- assumes ES,NOTHING
- ASC_CRLF EQU 0A0Dh ;ASCII Carriage return/Line Feed
- ASC_TAB EQU 9 ;ASCII Tab
- sBegin DATA
- EXTRN tabStops:WORD ;defined in edit manager
- EXTRN b$PTRFIL:WORD ;defined by runtime - current channel ptr
- CrLf DW ASC_CRLF ;for file line termination
- oMrsSaveDecl DW 0 ;used by SaveDeclares
- sEnd DATA
- sBegin CODE
- ;Table of opcodes used to search for DECLARE or CALL statements
- ;
- tOpDecl LABEL WORD
- opTabStart DECL
- opTabEntry DECL,opStDeclare
- opTabEntry DECL,opStCall
- opTabEntry DECL,opStCalls
- opTabEntry DECL,opStCallLess
- opTabEntry DECL,opEot
- sEnd CODE
- EXTRN B$BUFO:FAR
- EXTRN B$KILL:FAR
- sBegin CP
- assumes cs,CP
- ;*************************************************************
- ; ushort SaveTxdCur(ax:otxStart)
- ; Purpose:
- ; ASCII save the contents of the current text table
- ; Entry:
- ; ax = text offset to start saving text
- ; Exit:
- ; ax = size of last line output (=2 if trailing blank line)
- ; ps.bdpSrc is used
- ; Exceptions:
- ; Can cause runtime error (Out of memory, I/O errors)
- ;
- ;*************************************************************
- SaveTxdCur PROC NEAR
- DbChk Otx,ax
- push si
- push di
- sub di,di ;Init cbLastLine = 0
- mov [otxListNext],ax ;ListLine() updates [otxListNext]
- test [mrsCur.MRS_flags2],FM2_NoPcode ; document file?
- je GetOtxEndProg ; file is measured in Otxs, not lines
- DbAssertRel [otxListNext],e,0,CP,<SaveTxdCur:Not starting at the begining of file>
- push [mrsCur.MRS_pDocumentBuf]
- call S_LinesInBuf ; get # lines in document buffer
- jmp short SetMaximumSave
- GetOtxEndProg:
- call OtxEndProg ;ax = otx to Watch pcode
- SetMaximumSave:
- xchg si,ax ;si = otx to Watch pcode
- StLoop:
- mov ax,[otxListNext] ;ax=offset for next line to list
- cmp ax,si
- DJMP jae SlDone ;brif done with this text table
- test [mrsCur.MRS_flags2],FM2_NoPcode ; document file?
- je ListPcodeLine ; brif not, let lister get line
- push [mrsCur.MRS_pDocumentBuf] ; document table to list from
- push ax ; line to list
- push ps.PS_bdpSrc.BDP_cbLogical ; length of buffer
- push ps.PS_bdpSrc.BDP_pb ;pass ptr to dest buf
- call S_cbGetLineBuf ; AX = cBytes in line
- inc [otxListNext] ; bump pointer to next line
- mov [cLeadingSpaces],0 ; start with no leading spaces
- mov bx,[ps.PS_bdpSrc.BDP_pb]; BX = ptr to 0 terminated string
- CheckNextChar:
- cmp byte ptr [bx],' ' ; Is it a space
- jne GotLine ; brif not, say that we got line
- inc [cLeadingSpaces] ; indicate another space
- inc bx ; point to next character
- jmp CheckNextChar ; check it for a space
- ListPCodeLine:
- push ax ;pass offset to ListLine
- PUSHI ax,<DATAOFFSET ps.PS_bdpSrc> ;pass dst buf ptr to listline
- call ListLine ;ax=char count
- inc ax ;test for UNDEFINED
- jne NotOmErr ;brif out-of-memory
- jmp OmErrCP
- NotOmErr:
- dec ax ;restore ax = byte count
- GotLine:
- cmp [fLsIncluded],0
- jne StLoop ;brif line was part of $INCLUDE file
- test mrsCur.MRS_flags2,FM2_EntabSource ;do we need to entab leading
- ;blanks?
- jz NoEntab ;brif not
- mov cl,[cLeadingSpaces] ;cl = count of leading spaces
- or cl,cl ;any leading spaces?
- jnz EntabLeadingSpaces ;brif so, replace with tabs
- NoEntab:
- mov bx,[ps.PS_bdpSrc.BDP_pb]
- EntabCont:
- ; There is currently no need to call UpdChanCur here, because
- ; there is no chance of having nested open files during ascii save.
- DbAssertRel b$PTRFIL,ne,0,CP,<SaveTxdCur:Invalid channel>
- ; Call OutLine as we can not guarentee that the buffer
- ; pointed to by BX contains at least two more bytes.
- ; This is slower, but will not trash the heaps.
- mov di,ax ; DI = new "cbLastLine"
- inc di ; account for CRLF
- inc di
- call OutLine ; Print line and CRLF
- DJMP jmp SHORT StLoop
- SlDone:
- xchg ax,di ;ax = cb last line emitted
- pop di
- pop si
- ret
- SaveTxdCur ENDP
- ; We have a line with leading spaces which needs to be entabbed.
- ; We will convert spaces to tabs in the buffer, and return the
- ; new buffer char count, and a ptr to the start of the buffer.
- ;
- ; Entry:
- ; ax = count of chars in line buffer
- ; cl = count of leading spaces
- ; Exit:
- ; ax = adjusted count of chars in line buffer
- ; bx = ptr to first char in buffer
- ; Uses:
- ; bx,cx,dx
- EntabLeadingSpaces:
- push ax ;preserve buffer char count
- xchg ax,cx
- sub ah,ah ;ax = cLeadingSpaces
- mov dx,ax ;remember cLeadingSpaces
- mov cx,[tabStops] ;get user defined tabstop settings
- ; User interface guarantees tabStops will not be set to 0
- DbAssertRel cx,nz,0,CP,<tabStops=0 detected in Ascii save>
- div cl ;al=tab count, ah=space count
- mov bx,[ps.PS_bdpSrc.BDP_pb] ;bx=ptr to line buffer
- add bx,dx ;bx=ptr to first non-leading space
- sub dl,al
- sub dl,ah ;dx=excess space in buffer
- sub bl,ah ;backup over remaining spaces
- sbb bh,0
- xchg ax,cx
- sub ch,ch ;cx=tab count
- jcxz NoTabs ;brif none to replace
- mov al,ASC_TAB
- TabLoop:
- dec bx ;back up a char
- mov [bx],al ;replace space with tab
- loop TabLoop
- NoTabs:
- pop ax ;recover buffer char count
- sub ax,dx ;adust for removed spaces
- jmp EntabCont
- ;*************************************************************
- ; OutLine, OutCrLf
- ; Purpose:
- ; OutLine - Output line and CR-LF to current file
- ; OutCrLf - Output CR-LF to current file
- ; Entry:
- ; bx points to 1st byte to output
- ; ax = byte count
- ;
- ;*************************************************************
- OutLine PROC NEAR
- ; There is currently no need to call UpdChanCur here, because
- ; there is no chance of having nested open files during ascii save.
- DbAssertRel b$PTRFIL,ne,0,CP,<OutLine:Invalid channel>
- push ds ;pass segment of buffer
- push bx ;pass offset of buffer
- push ax ;pass length of buffer
- call B$BUFO ;output line via runtime
- ;fall into OutCrLf
- OutLine ENDP
- OutCrLf PROC
- ; There is currently no need to call UpdChanCur here, because
- ; there is no chance of having nested open files during ascii save.
- DbAssertRel b$PTRFIL,ne,0,CP,<OutCrLf:Invalid channel>
- push ds
- PUSHI ax,<dataOFFSET CrLf>
- PUSHI ax,2
- call B$BUFO ;output CR/LF via runtime
- ret
- OutCrLf ENDP
- ;*************************************************************
- ; RelShBuf
- ; Purpose:
- ; Release temporary text table used by SaveProcHdr.
- ; Called when we're done saving, or when an error occurs.
- ;
- ;*************************************************************
- RelShBuf PROC NEAR
- mov [txdCur.TXD_bdlText_cbLogical],0
- ;so TxtDiscard won't examine deleted txt
- call TxtDiscard ;discard temporary text table
- call TxtActivate ;make module's text table cur again
- mov [ps.PS_bdpDst.BDP_cbLogical],0 ;release space held by temp bd
- ret
- RelShBuf ENDP
- ;*************************************************************
- ; ushort SaveProcHdr(ax:otxProcDef)
- ; Purpose:
- ; ASCII save the current procedure's header.
- ;
- ; Entry:
- ; ax = otxProcDef = offset into procedure's text table to opBol for line
- ; containing SUB/FUNCTION statement. 0 if this table has no
- ; SUB/FUNCTION statement yet.
- ;
- ; Exit:
- ; ps.bdpSrc is used
- ; grs.fDirect = FALSE
- ; ax = 0 if no error, else Standard BASIC error code (i.e. ER_xxx)
- ;
- ; Exceptions:
- ; Can cause runtime error (Out of memory, I/O errors)
- ;
- ;*************************************************************
- SaveProcHdr PROC NEAR
- push si ;save caller's si,di
- push di
- mov di,ax ;di = otxProcDef
- push [grs.GRS_oPrsCur] ;pass current oPrs to PrsActivate below
- ;fill tEtTemp[] with DEFTYP's from start of proc table to SUB line
- mov ax,di ;ax = otxProcDef
- mov bx,dataOFFSET tEtTemp ;bx -> type table
- call OtxDefType
- ;move everything up to proc def from procedure's to temp text table
- PUSHI ax,<dataOFFSET ps.PS_bdpDst>
- push di ;pass otxProcDef
- call BdRealloc
- or ax,ax
- je JE1_ShOmErr ;brif out-of-memory error
- PUSHI ax,<dataOFFSET txdCur.TXD_bdlText>
- SetStartOtx ax
- push ax
- push [ps.PS_bdpDst.BDP_pb]
- push di ;pass otxProcDef
- call BdlCopyFrom
- ;Now we create a temporary text table for saving the synthetically
- ;generated procedure header. We must go through the following steps
- ; to do this:
- ; PrsDeactivate() --- causes module's text table to be made active
- ; TxtDeactivate() --- causes no text table to be made active
- ; TxtCurInit() --- make temp text table active
- ; put synthetically generated pcode into txdCur
- ; ASCII save this pcode buffer to the file
- ; TxtDiscard() --- discard temporary text table
- ; TxtActivate() --- make module's text table current again
- ; PrsActivate(oPrsSave)
- ;[flagsTM.FTM_SaveProcHdr] is non-zero while in critical state
- ; within function SaveProcHdr. Tells SaveFile's error cleanup
- ; to take special action.
- or [flagsTM],FTM_SaveProcHdr ;if err, remember to clean up
- call PrsDeactivate ;make module's text table active
- call TxtDeactivate ;causes no text table to be made active
- call TxtCurInit ;make temp text table active
- je ShOmErr ;brif out-of-memory error
- ;emit synthetic DEFxxx statements as transition from end of last
- ;text table to procedure definition line
- PUSHI ax,<dataOFFSET ps.PS_tEtCur>
- PUSHI ax,<dataOFFSET tEtTemp>
- SetStartOtx ax ;insert at start of text
- call InsertEtDiff
- JE1_ShOmErr:
- je ShOmErr ;brif out-of-memory error
- call OtxEndProg ;ax = otx to Watch pcode
- xchg si,ax ; = offset beyond synthetic DEFxxx stmts
- ;Append everything up to SUB line to temp table
- push si ;pass otx to Watch pcode
- push di ;pass otxProcDef
- call TxtMoveUp
- je ShOmErr ;brif out-of-memory error
- PUSHI ax,<dataOFFSET txdCur.TXD_bdlText>
- push si ;pass otx to Watch pcode
- push [ps.PS_bdpDst.BDP_pb]
- push di ;pass otxProcDef
- call BdlCopyTo
- call SqueezeDefs ;takes parm in si
- ;if setting of $STATIC/$DYNAMIC differs between procedure's header
- ;and where procedure will be listed in source file,
- ;insert pcode to change the state for the procedure,
- ;Note: fLsDynArrays's value will be changed by ListLine() when it
- ; lists the line emitted by InsertDynDiff (if any)
- SetStartOtx ax ;insert at start of text
- mov dh,[fLsDynArrays] ;dh = old $STATIC/$DYNAMIC state
- mov dl,[fProcDyn] ;dl = new $STATIC/$DYNAMIC state
- call InsertDynDiff
- je ShOmErr ;brif out of memory error
- SetStartOtx ax ;start saving at start of text
- call SaveTxdCur ;save procedure's header to file
- call RelShBuf ;release temp text tbl
- and [flagsTM],NOT FTM_SaveProcHdr ;reset critical section flag
- ;oPrs parm was pushed on entry to this function
- call PrsActivateCP
- sub ax,ax ;return no-error result
- ;al = error code
- ShExit:
- mov [ps.PS_bdpDst.BDP_cbLogical],0 ;release space held by temp bd
- or al,al ;set condition codes for caller
- pop di ;restore caller's si,di
- pop si
- ret
- ShOmErr:
- pop ax ;discard oPrs
- mov al,ER_OM ;return al = out-of-memory error
- jmp SHORT ShExit
- SaveProcHdr ENDP
- ;Cause runtime error "Out of memory"
- OmErrCP:
- mov al,ER_OM
- call RtError
- ;*************************************************************
- ; ONamOtherOMrs
- ; Purpose:
- ; Given an oNam in current mrs, convert it to an oNam
- ; in another mrs (which has a different name table).
- ; Entry:
- ; grs.oMrsCur = source oMrs
- ; ax = source oNam
- ; dx = target oMrs
- ; Exit:
- ; ax = target oNam (0 if out of memory error)
- ; flags set based upon return value.
- ;
- ;*************************************************************
- cProc ONamOtherOMrs,<NEAR>
- localV bufNam,CB_MAX_NAMENTRY
- cBegin
- cmp [grs.GRS_oMrsCur],dx
- je OnOExit ;brif source mrs = target mrs
- xchg ax,bx ;bx = oNam (save until CopyONamPb)
- push di
- push [grs.GRS_oRsCur] ;save caller's oRs -for RsActivate below
- mov di,dx ;di = target oMrs
- lea ax,bufNam
- push ax ;save ptr to string
- ; string ptr in ax
- ; oNam to CopyONamPb in bx
- cCall CopyONamPb,<ax,bx> ; ax = byte count
- push ax ;save byte count
- cCall MrsActivateCP,<di> ;activate target mrs
- pop cx ;cx = byte count
- pop ax ;ax = ptr to bufNam
- call ONamOfPbCb ;ax = target oNam (ax=Pb, cx=Cb)
- xchg di,ax ;di = target oNam
- call RsActivateCP ;re-activate caller's oRs
- ; parm was pushed on entry
- xchg ax,di ;ax = target oNam
- pop di ;restore caller's es,di
- OnOExit:
- or ax,ax ;set condition codes
- cEnd
- ;*************************************************************
- ; SaveDeclares
- ; Purpose:
- ; Generate synthetic DECLARE stmts for forward referenced
- ; SUBs and FUNCTIONs in this module as follows:
- ; Pass1:
- ; For every prs in system,
- ; reset FTX_TmpDecl
- ; if prs type is FUNCTION and prs is in mrs being saved,
- ; set FTX_TmpRef bit, else reset it
- ; Pass2:
- ; For every text table in this module
- ; Search text table for a reference to a SUB or FUNCTION
- ; if opStDeclare ref found
- ; set FTX_TmpDecl bit
- ; else if CALL, CALLS, implied CALL
- ; set FTX_TmpRef bit
- ; Pass3:
- ; For every prs in system,
- ; if FP_DEFINED and FTX_TmpRef bit are set, and FTX_TmpDecl bit is not,
- ; copy pcode for definition to module, changing opcode to opStDeclare,
- ; and changing the oNam for each formal parm and explicitly
- ; listing the TYPE.
- ;
- ; Exit:
- ; grs.fDirect = FALSE
- ; ax = 0 for out of memory error.
- ; flags set on value in ax
- ;*************************************************************
- ;----------------------------------------------------------------
- ; For every prs with a text table in system,
- ; reset FTX_TmpDecl
- ; if prs type is FUNCTION and prs is in mrs being saved,
- ; set FTX_TmpRef bit, else reset it
- ;----------------------------------------------------------------
- cProc SdPass1,<NEAR>
- cBegin
- and [txdCur.TXD_flags],NOT (FTX_TmpDecl OR FTX_TmpRef)
- ;start out by turning both bits off
- cmp [prsCur.PRS_procType],PT_FUNCTION
- jne Sd1ResetBits ;exit if SUB
- mov ax,[oMrsSaveDecl]
- cmp ax,[prsCur.PRS_oMrs]
- jne Sd1ResetBits ;exit if Func defined in another module
- ;for func in module, assume it is referenced. For external func
- ;refs, even qbi requires user have a DECLARE stmt for it.
- or [txdCur.TXD_flags],FTX_TmpRef ;turn on FTX_TmpRef bit
- Sd1ResetBits:
- mov ax,sp ;return TRUE for ForEachCP
- cEnd
- ;-----------------------------------------------------------------
- ; For every text table in module being saved:
- ; Search text table for a reference to a SUB or FUNCTION
- ; if opStDeclare ref found
- ; set FTX_TmpDecl bit
- ; else if CALL, CALLS, implied CALL
- ; set FTX_TmpRef bit
- ;-----------------------------------------------------------------
- cProc SdPass2,<NEAR>,<si>
- cBegin
- SetStartOtx si ;otxCur = start of text
- Sd2Loop:
- push si
- PUSHI ax,<CODEOFFSET tOpDecl>
- call TxtFindNextOp ;ax = otx to next opStDeclare opcode
- cmp dl,DECL_opEot
- je Sd2Exit
- xchg si,ax ;si = new otxCur
- GetSegTxtTblCur ;es = seg addr of text table
- mov ax,es:4[si] ;ax = oPrs field
- call PPrsOPrs ; es:bx points to prs structure
- ;all other regs preserved
- test BPTRRS[bx.PRS_flags],FP_DEFINED
- je Sd2Loop ;don't count references to native-code
- ; procedures, only those defined with
- ; a SUB/FUNCTION stmt
- mov al,FTX_TmpRef
- .errnz DECL_opStDeclare
- or dl,dl ;dl = 0 for DECLARE, non-zero for CALL
- jne Sd2SetBit ;brif CALL
- mov al,FTX_TmpDecl
- Sd2SetBit:
- or BPTRRS[bx.PRS_txd.TXD_flags],al
- jmp SHORT Sd2Loop
- Sd2Exit:
- mov ax,sp ;return TRUE for ForEachCP
- cEnd
- ;***
- ;GetWord
- ;Purpose:
- ; This header block added as part of revision [5]
- ;Preserves:
- ; All but ES, BX, and SI
- ;******************************************************************************
- GetWord PROC NEAR
- GetSegTxtTblCur ;es = seg addr of text table
- lods WORD PTR es:[si] ;ax = cntEos
- ret
- GetWord ENDP
- MoveWord PROC NEAR
- call GetWord
- jmp Emit16_AX ;emit cntEos operand
- ; and return to caller
- MoveWord ENDP
- ;------------------------------------------------------------------------------
- ; For every prs with a text table in system,
- ; if FP_DEFINED and FTX_TmpRef bit are set, and FTX_TmpDecl bit is not,
- ; copy pcode for definition to module, changing opcode to opStDeclare,
- ; and changing the oNam for each formal parm and explicitly
- ; listing the TYPE.
- ;
- ;------------------------------------------------------------------------------
- cProc SdPass3,<NEAR>,<si,di>
- localW oNamParm
- cBegin
- test [prsCur.PRS_flags],FP_DEFINED
- je J1_Sd3Exit ; don't count references to
- ; undefined procedures
- test [txdCur.TXD_flags],FTX_TmpRef
- je J1_Sd3Exit ;don't generate DECLARE for text tbl
- ; with no references in this module
- test [txdCur.TXD_flags],FTX_TmpDecl
- je EmitDecl ;don't generate DECLARE for prs which
- J1_Sd3Exit:
- jmp Sd3Exit ; already has a declare in this prs
- EmitDecl:
- mov ax,[prsCur.PRS_otxDef] ; ax = otx to opStSub/Function
- mov si,ax ;ax = si = text offset
- call OtxDefTypeCur ;fill ps.tEtCur with default types
- ; at definition of procedure
- mov ax,opBol
- call Emit16_AX
- mov ax,opStDeclare
- call Emit16_AX
- lodsw ;si=si+2 (points to cntEos parm)
- .errnz DCL_cntEos
- call MoveWord ;move cntEos from es:[si] to ps.bdpDst
- .errnz DCL_oPrs - 2
- call MoveWord ;move oPrs from es:[si] to ps.bdpDst
- .errnz DCL_atr - 4
- call GetWord ;ax = procAtr from es:[si]
- push ax ;save proc atr
- .errnz DCLA_procType - 0300h
- and ah,DCLA_procType / 100h ;ah = procType
- cmp ah,PT_FUNCTION
- jne NoProcType ;brif this is not a FUNCTION
- .errnz DCLA_Explicit - 0080h
- or al,al
- js NoProcType ;brif it was explicitly typed
- push [prsCur.PRS_ogNam]
- call ONamOfOgNam ; ax = oNam of this prs
- DbAssertRel ax,nz,0,CP,<txtsave.asm: ONamOfOgNam returned ax = 0>
- cCall OTypOfONamDefault,<ax> ; ax = default oTyp (ax)
- or al,DCLA_Explicit ;remember this was Explicitly typed
- pop dx
- mov ah,dh ;ax = new procAtr
- push ax
- ;top of stack = procAtr
- NoProcType:
- call Emit16 ;emit proc atr operand
- .errnz DCL_cParms - 6
- call GetWord ;ax = cParms operand from es:[si]
- mov di,ax ;di = cParms
- call Emit16_AX ;emit cParms operand
- inc di
- Sd3ParmLoop:
- dec di ;decrement parm count
- jz Sd3Exit ;brif done with parms
- .errnz DCLP_id - 0
- call GetWord ;ax = parm's oNam or oVar
- cCall oNamoVarRudeOrParse,<ax>;if we text not in rude map oVar
- ; to oNam
- mov [oNamParm],ax
- mov dx,[oMrsSaveDecl]
- call ONamOtherOMrs ;ax = equivalent oNam in module dx
- ; (es is preserved)
- je Sd3OmExit ;brif OM error (AX=0) to stop ForEach
- call Emit16_AX ; oVar in SS_PARSE or SS_EXECUTE
- .errnz DCLP_atr - 2 ;Formal parm attributes (PATR_xxx)
- call GetWord ;ax = formal parm atr
- push ax ;save parmAtr
- .errnz PATR_asClause AND 0FFh
- test ah,PATR_asClause / 100h
- jne Sd3AsClause ;brif 'id AS xxx'
- .errnz PATR_explicit AND 0FFh
- or ah,PATR_explicit / 100h ;in DECLARE, force it to be explicit
- Sd3AsClause:
- call Emit16_AX
- ; if not SS_RUDE, it is oTyp of user type.
- .errnz DCLP_oTyp - 4 ;Type of the formal parm
- call GetWord ;ax = oNam for <user type> if > ET_MAX
- pop bx ;bx = parmAtr
- .errnz PATR_asClause AND 0FFh
- .errnz PATR_explicit AND 0FFh
- test bh,(PATR_explicit OR PATR_asClause) / 100h
- jne NotImpl ;brif not implicitly typed
- push [oNamParm]
- call OTypOfONamDefault ;ax = default oTyp for parm (ax)
- NotImpl:
- cmp ax,ET_MAX
- jbe NotUserTyp ;brif it is a primitive type
- ;Since declares are inserted before any type declarations, we cannot
- ;insert any references to a type name in the declare. SOOO, we
- ;just always use as ANY for synthetic declares with user defined
- ;types.
- sub ax,ax ;ax = AS ANY
- NotUserTyp:
- call Emit16_AX
- jmp SHORT Sd3ParmLoop
- Sd3Exit:
- mov ax,sp ;return TRUE for ForEachCP
- Sd3OmExit:
- cEnd
- ;-------------------------------------------------------------
- ; SaveDeclares - main code
- ;-------------------------------------------------------------
- PUBLIC SaveDeclares ;for debugging only
- cProc SaveDeclares,<NEAR>,<si>
- cBegin
- DbAssertRelB [txdCur.TXD_scanState],e,SS_RUDE,CP,<SaveDeclares:TxdCur not in SS_RUDE>
- call PrsDeactivate ;make module's txt tbl active
- mov ax,[grs.GRS_oMrsCur]
- mov [oMrsSaveDecl],ax
- test [mrsCur.MRS_flags2],FM2_Include ;is this an include mrs?
- jne SdGoodExit ;don't insert decls into include
- ;mrs's. Re-Including could break
- ;a previously running program.
- ;For each prs in system which has a text table:
- mov al,FE_PcodeMrs+FE_PcodePrs+FE_SaveRs
- mov bx,CPOFFSET SdPass1 ;bx = adr of function to call
- call ForEachCP
- ;For each text table in module being saved:
- mov al,FE_CallMrs+FE_PcodePrs+FE_SaveRs
- mov bx,CPOFFSET SdPass2 ;bx = adr of function to call
- call ForEachCP
- sub ax,ax
- mov [ps.PS_bdpDst.BDP_cbLogical],ax
- call SetDstPbCur
- ;For each prs in system which has a text table:
- mov al,FE_PcodeMrs+FE_PcodePrs+FE_SaveRs
- mov bx,CPOFFSET SdPass3 ;bx = adr of function to call
- call ForEachCP
- je SdExit ;brif out-of-memory
- SetStartOtx si ;insert DECLAREs at start of module
- call TxtInsert
- je SdExit ;brif out-of-memory
- SetStartOtx si ;otxInsert = start of text
- mov bx,[ps.PS_bdpDst.BDP_cbLogical] ;pass cbInserted in bx
- or bx,bx ;was any pcode inserted?
- je NoDeclaresInserted ;brif not
- or [mrsCur.MRS_flags2],FM2_Modified ;set modified bit so compiler
- ;will compile same source as QBI for
- ;MakeExe.
- push bx ;save cbInsert
- call DrawDebugScrFar ;update list windows for inserted text
- pop bx ;restore bx=cbInsert
- NoDeclaresInserted:
- call TxtInsUpdate
- SdGoodExit:
- mov ax,sp ;return non-zero (not out-of-memory)
- SdExit:
- or ax,ax ;set condition codes
- cEnd
- ;*************************************************************
- ; SaveAllDeclares
- ; Purpose:
- ; Generate synthetic DECLARE stmts for forward referenced
- ; SUBs and FUNCTIONs for every module in the system.
- ; Called by UI before MakeExe to ensure that Compiler
- ; will compile same source as interpreter. This solves
- ; the situation for a QB2/3 program is loaded and works
- ; correctly for QBI, but will not compile in BC. If we
- ; have inserted synthetic declares, or altered the pcode
- ; in some way, we need to make sure that the dirty bit
- ; gets set for the module.
- ; Entry:
- ; none.
- ; Exit:
- ; grs.fDirect = FALSE
- ; ax = 0 for no error, else QBI standard error code.
- ;*************************************************************
- cProc SaveAllDeclares,<PUBLIC,FAR>
- cBegin
- ;For each mrs in system which has a pcode text table:
- mov al,FE_PcodeMrs+FE_CallMrs+FE_SaveRs
- mov bx,CPOFFSET SaveDeclares ;bx = adr of function to call
- call ForEachCP
- mov ax,ER_OM ;default Out of memory error
- je SaveAllDeclaresExit ;brif out-of-memory
- sub ax,ax
- SaveAllDeclaresExit:
- cEnd
- ;*************************************************************
- ; ushort AsciiSave()
- ; Purpose:
- ; ASCII save the current module (with all its procedures)
- ;
- ; Exit:
- ; grs.fDirect = FALSE
- ; ps.bdpSrc is used
- ; ax = 0 if no error, else Standard BASIC error code (i.e. ER_xxx)
- ;
- ; Exceptions:
- ; Can cause runtime error (Out of memory, I/O errors)
- ;
- ;*************************************************************
- cProc AsciiSave,<NEAR>,<si>
- cBegin
- call AlphaBuildORs ; build sorted list of all oRs's
- or ax,ax ;set flags based on returned value
- mov ax,ER_OM ;prepare to return Out-of-memory error
- je AsDone ;brif error
- call PrsDeactivate ;make module's txt table active
- sub ax,ax
- mov [fLsDynArrays],al ;default state is $STATIC
- DbAssertRel ax,e,0,CP,<AsciiSave: ax!=0> ;SaveTxdCur needs ax=0
- ;ax = otx of 1st line in current text table to be written to file
- AsLoop:
- call SaveTxdCur ;save module/procedure text table
- test [mrsCur.MRS_flags2],FM2_NoPcode ; document file?
- jne NotModuleText ; brif so, never add blank line
- cmp ax,2 ;was last line a blank one?
- jbe NotModuleText ;brif so
- call OutCrLf ;output a blank line so comment blocks
- ;are associated with correct text tbls
- NotModuleText:
- call OtxDefTypeEot ;fill ps.tEtCur with default types
- ; at end of module/procedure
- call NextAlphaPrs ;activate next procedure in module
- or ax,ax ;set flags
- je AsDone ;brif no more procedures in module
- SetStartOtx ax
- test [prsCur.PRS_flags],FP_DEFINED
- je ProcNotDefined ;brif no SUB/FUNCTION stmt
- push [prsCur.PRS_otxDef] ;push offset to opStSub/opStFunction
- call OtxBolOfOtx ;ax = text offset for 1st line of SUB
- ProcNotDefined:
- mov si,ax ;si = ax = otxProcDef
- call SaveProcHdr ;save proc hdr(ax) (may contain some
- ; synthetically generated statements
- jne AsDone ;brif error
- xchg ax,si ;ax = otxProcDef
- jmp SHORT AsLoop
- ;al = 0 if no error, else standard QBI error code
- AsDone:
- cEnd ;AsciiSave
- ;****************************************************************************
- ;SaveModName - save the name of the current module to the file
- ;
- ;Purpose:
- ; Used by Save to save the name of each module in a .MAK file.
- ;Entry:
- ; The .MAK file is open to current channel
- ; si points to static buffer holding name of the MAK file's directory.
- ; di points to static buffer which can be used to hold module's name
- ;Exceptions:
- ; Assumes caller called RtSetTrap to trap runtime errors.
- ;
- ;****************************************************************************
- SaveModName PROC NEAR
- mov ax,di ; pDest (parm to CopyOgNamPbNear)
- mov bx,[mrsCur.MRS_ogNam] ; ogNam (parm to CopyOgNamPbNear)
- call CopyOgNamPbNear ; copies name to buffer, returns
- ; ax = cbName
- mov bx,di
- add bx,ax ; add cbName
- mov BYTE PTR [bx],0 ; zero terminate
- ;MakeRelativeFileSpec(szFilename, szMakDirectory)
- cCall MakeRelativeFileSpec,<di,si> ;convert szFilename to relative
- ; path from szMakDirectory if possible
- cCall CbSz,<di> ;ax = length of result path
- ;ax = size of line to output
- mov bx,di ;bx points to start of line to output
- call OutLine ;output the line
- ret
- SaveModName ENDP
- ;****************************************************************************
- ; FNotMainModule
- ; Purpose:
- ; Called via ForEachCP to see if there is any pcode module
- ; that is not the main module (i.e. to see if this is a
- ; multiple-module program.
- ; Exit:
- ; Return 0 in ax if current module is not main-module
- ; else return non-zero in ax
- ;
- ;****************************************************************************
- FNotMainModule PROC NEAR
- mov ax,[grs.GRS_oMrsCur]
- cmp ax,[grs.GRS_oMrsMain]
- mov ax,sp ;prepare to return non-zero
- je FNotMainExit
- sub ax,ax ;return 0 (not main module)
- FNotMainExit:
- ret
- FNotMainModule ENDP
- ;*************************************************************
- ; SaveMakFile
- ; Purpose:
- ; Called by SaveFile to see if we're saving the main module
- ; of a multi-module program. If so, this creates <filename>.MAK
- ; file and writes the names of all modules in the program.
- ; Entry:
- ; mrsCur.ogNam is current module's filename
- ; Exit:
- ; ax = error code (0 if none), condition codes set
- ; Exceptions:
- ; assumes caller has called SetRtTrap to trap runtime errors
- ;
- ;*************************************************************
- cProc SaveMakFile,<NEAR>,<si,di>
- localV szDir,FILNAML
- localV filenameNew,FILNAML ; size expected by runtime routines
- ; used for filename normalization
- localV sdFilenameNew,<SIZE SD>
- cBegin
- mov ax,[grs.GRS_oMrsMain]
- cmp ax,[grs.GRS_oMrsCur]
- jne SmfGood ;brif this isn't main module
- mov bx,si ;bx = psdFilename
- lea si,[sdFilenameNew] ;si = &sdFilenameNew
- lea di,[filenameNew]
- mov [si.SD_pb],di ; set up string descr.
- call MakFilename ;fill di with <moduleName>.MAK
- jne SmfExit ;brif Bad File Name
- mov al,FE_PcodeMrs+FE_CallMrs+FE_SaveRs
- mov bx,CPOFFSET FNotMainModule ;bx = adr of function to call
- call ForEachCP ;ax=0 if multi-module program
- je MultiModules ;brif multi-module program is loaded
- push di ;pass ptr to szFilenameNew
- call DelFile ;delete filename.MAK
- jmp SHORT SmfGood ;exit if not multi-module program
- ;Open filename in sdFilename (si) (.MAK file) and write all module names to it
- MultiModules:
- ;If we could assume DOS 3.0 or greater, (we can't yet) we could set
- ;dx to (ACCESS_WRITE OR LOCK_BOTH) SHL 8 OR MD_SQO
- mov dx,MD_SQO
- call OpenChan ;al = error code (0 if no error)
- jne SmfExit ;brif errors
- ;fill si with sz for directory of .MAK file
- lea si,szDir ;si points to working static buffer
- push di ;pass pbSrc (filenameNew)
- push si ;pass pbDst (szDir)
- mov bx,[sdFilenameNew.SD_cb]
- push bx ;pass byte count
- mov BYTE PTR [bx+si],0 ;0-terminate destination
- call CopyBlk ;copy module name to static buffer
- push si ;pass szDir
- call FileSpec ;ax points beyond pathname
- xchg bx,ax ;bx points beyond pathname
- mov BYTE PTR [bx-1],0 ;0-terminate szDir
- ;Save the name of the Main Module first, so it will be loaded first
- ;si points to szDir
- ;di points to filenameNew (will be used for temp buffer)
- call SaveModName ;write main module's relative path
- call MrsDeactivate ;start writing other module names
- SmLoop:
- call NextMrsFile_All ;make next mrs active
- inc ax ;test for UNDEFINED (end of mrs list)
- je SmDone ;brif done with all mrs's
- dec ax ;restore ax = module's name
- cmp ax,[grs.GRS_oMrsMain]
- je SmLoop ;brif this is MAIN mod (already output)
- test [mrsCur.MRS_flags2],FM2_NoPcode OR FM2_Include
- jne SmLoop ;skip document and include mrs's
- call SaveModName
- jmp SHORT SmLoop
- SmDone:
- push [grs.GRS_oMrsMain] ;we know the main module was active
- call MrsActivateCP ; on entry - reactivate it on exit
- call CloseChan ;close [chanCur]
- SmfGood:
- sub ax,ax
- SmfExit:
- or ax,ax ;set condition codes for caller
- cEnd
- ;*************************************************************
- ; ushort SaveFile()
- ; Purpose:
- ; Open the specified file and save program to it.
- ;
- ; Entry:
- ; mrsCur.ogNam = filename to be saved.
- ; (the filename need not be 0-byte terminated)
- ; mrsCur.flags2 FM2_AsciiLoaded is TRUE for ASCII Save
- ; FOR EB: parm1 = mode for opening file
- ;
- ; Exit:
- ; ps.bdpSrc is used
- ; grs.fDirect = FALSE
- ; ax = 0 if no error, else Standard BASIC error code (i.e. ER_xxx)
- ;
- ;*************************************************************
- cProc SaveFile,<PUBLIC,FAR,NODATA>,<si>
- localV FileName,FILNAML
- localV sdFileName,<SIZE SD>
- cBegin
- mov ax,-MSG_Saving ;display Saving msg in intense video
- call StatusMsgCP ; to tell user we're loading
- call AlphaORsFree ;release table of sorted oRs's
- ; (user interface may have chosen
- ; a new name for this mrs)
- push [grs.GRS_oRsCur] ;save mrs/prs - restored on exit
- call RtPushHandler ;save caller's runtime error handler
- ; could be called by LoadFile->NewStmt
- ; (NOTE: alters stack pointer)
- SetfDirect al,FALSE ;turn off direct mode
- mov ax,CPOFFSET SfDone ;if any runtime errors occur,
- call RtSetTrap ;branch to SfDone with sp,di =
- ;current values
- ; doesn't have to be recompiled
- call ModuleRudeEdit
- call SaveDeclares ;generate synthetic DECLARE stmts
- ; for forward-referenced
- mov ax,ER_OM ;default to OM error
- je SfDone ;brif error
- lea si,[sdFileName] ;cant use buffers here used for
- lea ax,[FileName] ;load because we may need to save
- mov [si.SD_pb],ax ;current module during fileopen
- mov bx,[mrsCur.MRS_ogNam]
- call CopyOgNamPbNear ; ax = number of chars copied
- mov [si.SD_cb],ax
- call SaveMakFile ;create <filename>.MAK if main
- ; program of multi-module program.
- jne SfDone ;brif errors
- ;If we could assume DOS 3.0 or greater, (we can't yet) we could set
- ;dx to (ACCESS_WRITE OR LOCK_BOTH) SHL 8 OR MD_SQO
- mov dx,MD_SQO
- call OpenChan ;[chanCur] = channel #
- jne SfDone ;brif error
- DoAsciiSave:
- call AsciiSave ;al = errCode
- ;We're done trying to write the file, now try to close it.
- ;Closing the file can cause I/O errors when close flushes the buffer.
- ;al = 0 if no error, else standard QBI error code
- SfDone:
- sub ah,ah ;ax = error code
- SfDone2:
- xchg si,ax ;si = return value
- test [flagsTM],FTM_SaveProcHdr
- je NoShCleanup ;brif SaveProcHdr was not in critical
- ; section.
- call RelShBuf ;release temp text tbl used by
- ; SaveProcHdr
- NoShCleanup:
- call RtFreeTrap ;free previous trap address
- mov ax,CPOFFSET SfGotErr ;if any runtime errors occur,
- call RtSetTrap ;branch to SfGotErr with sp,bp,si,di
- ;set to current values
- call CloseChan ;close file before kill
- ; (sets ChanCur = 0)
- cCall RtFreeTrap ; release error handler
- test si,7FFFh ; test low 15 bits for error code
- je SfNoErr ;brif no error before close
- xor ax, ax ; no error during close
- ;If we got an error during save, delete partially created file
- SfGotErr:
- test si, 7fffh ; do we already have an error
- jnz SfTestDelFile ; brif so, use it
- or si, ax ; else add in new error
- ; Only delete the file if we actually created and started to save
- ; a binary file. We don't want to delete an existing file if we
- ; got an error on or before the open, and we also don't want to
- ; delete a partially written ascii file.
- SfTestDelFile:
- or si,si ; got to BinarySave?
- jns SfExit ; no, then don't kill the file
- push di
- mov ax,CPOFFSET SfKillErr ; trap & ignore any runtime errors
- cCall RtSetTrap ; in KILL
- sub sp,((FILNAML+SIZE SD+2)+1) AND 0FFFEh ;[3] create a fake sd
- ; on the stack
- mov di,sp
- add di,6 ; pnt to strt of where string will be
- mov [di-2],di ; setup pb part of fake sd
- mov ax,di ; parm to CopyOgNamPbNear
- mov bx,[mrsCur.MRS_ogNam] ; parm to CopyOgNamPbNear
- call CopyOgNamPbNear ; copy name onto stack, ax = cbName
- sub di,4 ; di = pFakeSd
- mov [di],ax ; set up cb part of fake sd
- cCall B$KILL,<di> ; call rt to delete file
- add sp,((FILNAML+SIZE SD+2)+1) AND 0FFFEh ;[3] restore stack ptr
- SfKillErr: ; branched to if error during KILL
- pop di
- jmp SHORT SfExit
- SfNoErr:
- and [mrsCur.MRS_flags2],NOT (FM2_Modified or FM2_ReInclude)
- and [mrsCur.MRS_flags3],NOT FM3_NotFound ;If the user told
- ;us to save the file, we have
- ;found it.
- test [mrsCur.MRS_flags2],FM2_Include
- je SfExit ;brif this is not an $INCLUDE file
- or [flagsTm],FTM_reInclude ;re-parse all $INCLUDE lines in
- ;all modules before next RUN
- SfExit:
- and [flagsTM],NOT FTM_SaveProcHdr ;reset critical section flag
- call RtPopHandler ;restore caller's runtime error handler
- ; (saved on stack by RtPushHandler)
- call RsActivateCP ;restore caller's mrs/prs
- call StatusMsg0CP ;tell user interface we're done saving
- xchg ax,si ;restore ax = error code
- and ah,7Fh ; clear BinarySave flag bit
- cEnd
- sEnd CP
- end