antoine-source/appleworksgs/WP/Src/Pars.aii
2023-03-04 03:45:20 +01:00

1 line
37 KiB
Plaintext
Executable File

*****************************************************************************************************
; WP Paragraph Manipulation Routines
;
; This file contains the routines used to manipulate the paragraph data structure used by WP. The
; paragraph structure is described below:
;
; The paragraph data structure is an array from 1..W_LastP of paragraph info blocks:
;
; W_pBlockHand gequ 0 : handle to the block that the par is in
; W_pOffset gequ 4 : offset into this block that starts the par
; W_pAttr gequ 6 : attribute word for the par
; W_pRulerHand gequ 8 : handle to the ruler that governs this par
; W_pPixels gequ 12 : number of pixels tall this par is
; W_pLineHand gequ 14 : handle to the line struct for this par (Purgeable)
; W_pLastLine gequ 18 : number of last line in the par+1, cr is 0
; W_pBytes gequ 20 : equate for size of paragraph block.
;
*****************************************************************************************************
load 'macros.dump'
include 'driver.equ'
include 'wp.equ'
W_StartMaxP equ 10
W_StartBlockSize equ $1000
W_GrowAmount equ $400
IMPORT D_SetFileChanged
IMPORT D_Deref
IMPORT D_GrowHandle
IMPORT D_GrowLHandle
IMPORT D_MainZPage
IMPORT D_NeedHand
IMPORT W_CurDoc
IMPORT W_FindFont
IMPORT W_GetLRecPtr
IMPORT W_GetLineRec
IMPORT W_LastP
IMPORT W_MakeLines
IMPORT W_MaxP
IMPORT W_PHandle
IMPORT W_PPtr
IMPORT W_RulBits
IMPORT W_RulBytes
IMPORT W_Selected
IMPORT W_StartLine
IMPORT W_StartOffset
IMPORT StdRuler
IMPORT W_StartPar
IMPORT W_ValidLines
IMPORT W_WPRuler
IMPORT W_Stuff
ENTRY W_GetAddr
ENTRY W_GetLastLGuts
ENTRY W_GetParRec
ENTRY W_LessRoom
ENTRY W_MakeEmptyBlock
ENTRY W_MakeNewParRec
ENTRY W_MakeRoom
ENTRY W_NewRuler
ENTRY W_UseRuler
*****************************************************************************************************
; W_InitPars ( )
;
; This routine is called to setup and empty document. It will create a new paragraph array and a
; single carriage return paragraph.
;
; Note: Memory errors are returned.
W_InitPars PROC EXPORT
;Using wpglobals
;Using W_ParData
local ptr:l,TextPtr:l,RulerHand:l,TextBlock:l
error err
begin
; Ask for initial paragraph array handle. If memory error then exit with error.
call D_NeedHand,in=(#W_StartMaxP*W_pBytes:l),out=(ax:l),err=err
jcs exit
; Lock down paragraph handle and get pointer to first paragraph entry.
movelong ax,W_PHandle
jsl D_Deref
movelong ax,W_PPtr
moveword #W_StartMaxP,W_MaxP
moveword #1,W_LastP
rcall W_GetParRec,in=(#1:a),out=(ptr:ax)
; Get text block for 1st paragraph.
call W_MakeEmptyBlock,out=(TextBlock:l),err=err
jcs @killpar
movelong TextBlock,[ptr]
; Initialize 1st paragraph entry in paragraph array.
moveword #W_BHeader,[ptr]:#W_pOffset
moveword #0,[ptr]:#W_pAttr
movelong #0,[ptr]:#W_pLineHand
moveword #1,[ptr]:#W_pLastLine
; Get ruler for 1st paragraph. If memory error then clean up and exit with error. Else use ruler.
call W_NewRuler,out=(RulerHand:l),err=err
bcs @killtext
movelong RulerHand,[Ptr]:#W_pRulerHand
call W_UseRuler,in=(#1:w,RulerHand:l)
; Make room for initial text block contents - if error then clean up and exit.
call W_MakeRoom,in=(#1:w,#0:w,#W_TextHeader+1:w),err=err
bcs @killruler
; Set up contents of 1st paragraph text block - single carriage return.
rcall W_GetAddr,in=(#1:a,#0:x),out=(TextPtr:ax)
moveword #W_StandFont,[TextPtr]
moveword #W_StandStyle,[TextPtr]:#2
moveword #Black,[TextPtr]:#4
movebyte #cr,[TextPtr]:#W_TextHeader
; Create lines for 1st paragraph and initialize globals. If we can't make lines then return memory
; error.
call W_MakeLines,in=(#1:w),err=err
bcs @killruler
stz W_StartLine
stz W_Selected
moveword #1,W_StartPar
moveword #W_TextHeader,W_StartOffset
bra exit
; Memory error occurred so clean up allocated memory.
@killruler tool _DisposeHandle,in=(RulerHand:l)
@killtext tool _DisposeHandle,in=(TextBlock:l)
@killpar tool _DisposeHandle,in=(W_PHandle:l)
exit return
ENDP
****************************************************************
* W_GetAddr - returns the physical address of par a, offset x
* returns address in ax
W_GetAddr PROC EXPORT
;Using D_GlobalData
ParRec equ 0
handle equ 4
ptr equ 8
tay
phd
lda >D_MainZPage
tcd
phx ;D_Save offset for later
tya
jsl W_GetParRec
movelong ax,ParRec
movelong [ParRec],handle
movelong [handle],ptr
ldx ptr+2
ldy #W_pOffset
lda [ParRec],y
clc
adc ptr
bcc NoInc
inx
clc
NoInc adc 1,s
bcc NoInc2
inx
NoInc2 ply
pld
rtl
ENDP
****************************************************************
* W_GetParRec - gets the physical address of par a's record structure
* adress is returned in ax
* NOTE!!! this must be changed as W_pBytes is changed. Hard-wired.
W_GetParRec PROC EXPORT
;Using wpglobals
;Using D_GlobalData
tay
phd
lda >D_MainZPage
tcd
ldx W_PPtr+2
tya
dec a ;since pars start with 1
asl a
asl a
sta 2 ;the times 4 part
asl a
bcc NoInca
inx ;if over here, takes 2 inx
inx
NoInca
asl a ;the times 16 part
bcc NoInc
inx
clc
NoInc
adc 2 ;add times4 with times16
bcc NoInc2
inx
clc
NoInc2
adc W_PPtr ;add to Par ptr offset
bcc NoInc3
inx
NoInc3
pld
rtl
ENDP
*****************************************************************************************************
; W_MakeEmptyBlock ( ): BlockHandle:long
;
; This routine is called to allocate a new empty text block and initializes its header counts.
W_MakeEmptyBlock PROC EXPORT
;Using W_ParData
output BlockHand:l
local ptr:l
error err
begin
call D_NeedHand,in=(#W_StartBlockSize:l),out=(ax:l),err=err
bcs @exit
movelong ax,BlockHand
movelong [BlockHand],ptr
moveword #W_StartBlockSize,[ptr]:#W_BSize
moveword #W_BHeader,[ptr]:#W_BUsed
@exit return
ENDP
*****************************************************************************************************
; W_DoRoom ( Paragraph:word, Offset:word, Bytes:word )
;
; This routine is called to adjust the given paragraph's text block by the given number of bytes.
; Bytes is a signed number possibly negative. If negative then call LessRoom, else use MakeRoom.
W_DoRoom PROC EXPORT
lda 4,s ;look at bytes
bpl W_MakeRoom
eor #$ffff ; negate into a positive value to pass LessRoom.
inc a
sta 4,s
brl W_LessRoom
ENDP
*****************************************************************************************************
; W_MakeRoom ( Paragraph:word, Offset:word, Bytes:word )
;
; This routine is called to make a gap in the text for the given paragraph, at the given offset,
; of Bytes in size. If insufficient space exists in the block then it will be split or grown as
; needed. Memory errors are returned.
;
; Note: Assumes affected blocks are unlocked.
W_MakeRoom PROC EXPORT
;Using wpglobals
;Using W_ParData
EXPORT NotLast
EXPORT W_CurrentBlockHandle
EXPORT W_CurrentBlockHandle2
input par:w,offset:w,bytes:w
local BlockPtr:l,BlockHand:l,newsize:w,ParPtr:l,LastParPtr:l
local used:w,newmax:w,BlockHand2:l,BlockPtr2:l,ParPtr2:l
local addbytes:w,CurPar:w
error err
begin
; Clear error status and current block handles. Current block handles are used to keep track of
; which handles we are using so that if the out of memory queue is called it won't try to collapse
; text/rulers for blocks we are in the process of changing!
stz err
stzl W_CurrentBlockHandle
stzl W_CurrentBlockHandle2
; If insertion gap size is zero then simply exit with no error, else we are manipulating the document
; so go ahead and set file changed bit.
lda bytes
jeq exit
call D_SetFileChanged,in=(W_CurDoc:l)
; Try to make gap in text block {main outer loop}. Get text block for the given paragraph.
TryAgain rcall W_GetParRec,in=(par:a),out=(ParPtr:ax)
movelong [ParPtr],BlockHand
movelong [BlockHand],BlockPtr
; Branch if not enough room exists in the current block to handle the growth. If block is already
; of StartBlockSize then
ldy #W_BUsed
lda [BlockPtr],y
sta used
clc
adc bytes
sta newsize
jcs NoRoom
cmpw newsize,[BlockPtr]
bcc IsRoom
cmpw newsize,#W_StartBlockSize
jcs NoRoom
; Grow the text block to StartBlockSize (obviously it has been collapsed to <4k). Remember the
; dialog that we are mucking with so that collapse rulers will not try to collapse the text block
; that we are trying to grow! If we can not grow the text block then try to split it and create a
; new one. (just like if we couldn't get the room).
movelong BlockHand, W_CurrentBlockHandle
stzl W_CurrentBlockHandle2
call D_GrowHandle,in=(#0:w,#W_StartBlockSize:w,BlockHand:l),err=err
jcs NoRoom
; Successfully grew the text block - set its new size.
movelong [BlockHand],BlockPtr
moveword #W_StartBlockSize,[BlockPtr]:#W_BSize
; Enough room exists in the text block, so make the gap and update used size and other ptrs.
IsRoom rcall W_GetAddr,in=(par:a,offset:x)
phx ;src high
pha ;src low
phx ;dest high
clc
adc bytes
pha ;dest low
bcc @noinc
inx
txa
sta 3,s ; source & dest now on stack.
@noinc pea 0 ; length high word - never moving more than 64k
lda used
sec
ldy #W_pOffset
sbc [ParPtr],y
sbc offset ; used-(paroffset(inblock)+offset(inpar))
pha
_BlockMove ; mem move
; Update the used count in the block. Get pointer to last paragraph that needs to be have its ptr
; updated. While paragraphs left to go and they share the same text block - update paragraph pointers
; to reflect gap insertion. Exit with error status still clear. - succeeded.
moveword newsize,[BlockPtr]:#W_BUsed
rcall W_GetParRec,in=(W_LastP:a),out=(LastParPtr:ax)
bra @loopchk
@loop cmpl [ParPtr],BlockHand
bne @endloop
ldy #W_pOffset
addword [ParPtr]:y,bytes,[ParPtr]:y
@loopchk addwl #W_pBytes,ParPtr
cmpl LastParPtr,ParPtr
bcs @loop
@endloop brl exit
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; Either we were unable to grow the paragraph's current text block to allow for the gap size or it
; was already 4k so we want to perform a split. Three cases exist:
;
; 1) Paragraph is already in a block by itself.
; 2) Paragraph is last paragraph to use the text block we want to split.
; 3) Paragraph is not last to use text block.
;
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; Check if only paragraph to use text block. If not first paragraph check if previous paragraph had
; same text block, and if not last paragraph check if next paragraph had same text block.
NoRoom movelong [BlockHand],BlockPtr
cmpw par,#1
beq @nonebefore
dec a
jsl W_GetParRec
movelong ax,ParPtr
cmpl [ParPtr],BlockHand
beq @NotOnly
@nonebefore cmpw par,W_LastP
beq IsOnly
inc a
jsl W_GetParRec
movelong ax,ParPtr
cmpl [ParPtr],BlockHand
bne IsOnly
@NotOnly brl NotAlone
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; CASE 1: Paragraph is already in a block by itself.
;
; In this case we grow the text block beyond 4k upto 64k. If text block will exceed 64k then exit
; with memory error. Make sure to remember text block we are trying to grow so collapse rulers/text
; in the out of memory queue won't try to shrink what we're growing.
IsOnly ldy #W_BUsed
lda [BlockPtr],y
clc
adc bytes
bcs @gomemerr
addword newsize,#W_GrowAmount,newmax
bcs @gomemerr
stzl W_CurrentBlockHandle2
movelong BlockHand,W_CurrentBlockHandle
call D_GrowHandle,in=(#0:w,newmax:w,BlockHand:l)
bcc @case1ok
@gomemerr brl domemerr
; Succeeded in growing text block so update used and max counts.
@case1ok movelong [Blockhand],BlockPtr
moveword newmax,[BlockPtr] ; update max
moveword newsize,[BlockPtr]:#W_BUsed ; update used
; Enough room exists in the text block, so make the gap and return with error status clear. Restore
; the paragraph pointer since NoRoom above could have left it pointing to either previous or next
; paragraph instead.
rcall W_GetParRec,in=(par:a),out=(ParPtr:ax)
rcall W_GetAddr,in=(par:a,offset:x)
phx ; src high
pha ; src low
phx ; dest high
clc
adc bytes
pha ; dest low
bcc @noinc
inx
txa
sta 3,s
@noinc pea 0 ; length high word - never more than 64k
lda used
sec
ldy #W_pOffset
sbc [ParPtr],y
sbc offset ; used-(paroffset(inblock)+offset(inpar))
pha
_BlockMove ; mem move
brl exit
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; Check if paragraph is last paragraph to use the text block. If is last paragraph in the document
; then we will need to create a new block for it (don't need to check to see if it will fit in next
; block - there is none). Addbytes = bytes - (used-offset).
NotAlone rcall W_GetParRec,in=(par:a),out=(ParPtr:ax)
subword [BlockPtr]:#W_BUsed,[ParPtr]:#W_pOffset,a
addword a,bytes,addbytes
cmpw par,W_LastP
jeq MakeNewOne
inc a
jsl W_GetParRec
movelong ax,ParPtr2
cmpl [ParPtr2],BlockHand
jeq NotLast
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; CASE 2: Paragraph is last paragraph to use the text block.
;
; In this case we need to check to see if the paragraph will fit in the next text block. If not we
; need to create a new one, else make gap at start of next text block. Update pointers for all other
; paragraphs using the same text block.
IsLast movelong [ParPtr2],BlockHand2
movelong [BlockHand2],BlockPtr2
addword addbytes,[BlockPtr2]:#W_BUsed,a
cmpw a,[BlockPtr2]:#W_BSize
jcs MakeNewOne
lda par
inc a
ldx #0
jsl W_GetAddr
phx ;src high
pha ;src low
phx ;dest high
clc
adc addbytes
pha ;dest low
bcc @noinc
inx
txa
sta 3,s
@noinc pea 0 ; length high word - never more than 64k
pushword [BlockPtr2]:#W_BUsed
_BlockMove ;mem move
ldy #W_BUsed
addword addbytes,[BlockPtr2]:y,[BlockPtr2]:y
rcall W_GetParRec,in=(W_LastP:a),out=(LastParPtr:ax)
@loop cmpl [ParPtr2],BlockHand2
bne @endloop
ldy #W_pOffset
addword [ParPtr2]:y,addbytes,[ParPtr2]:y
addwl #W_pBytes,ParPtr2
cmpl LastParPtr,ParPtr2
bcs @loop
@endloop bra GotRoom
; Allocate new text block for the paragraph. Either its the last paragraph in the document or there
; was not enough room in the text block of the next paragraph after it. If memory error then return
; it and exit with carry set.
MakeNewOne movelong BlockHand,W_CurrentBlockHandle
stzl W_CurrentBlockHandle2
call W_MakeEmptyBlock,out=(BlockHand2:l)
jcs domemerr
; If we need more than 4k then we have to resize the empty block we just got. If resize fails or
; will generate a >64k text block then return with memory error. Note: don't want out of memory
; queue trying to shrink the handle we're trying to grow! If we can't resize the block make sure
; we dispose of it.
cmpw addbytes,#W_StartBlockSize
bcc GotRoom
movelong BlockHand2,W_CurrentBlockHandle
addword addbytes,#W_GrowAmount,a
bcs @killblock2
@growit sta newmax
pea 0
pha
pushlong BlockHand2
jsl D_GrowHandle
bcc @gotit
@killblock2 tool _DisposeHandle,in=(BlockHand2:l)
brl domemerr
; Successfully resized the block - set its max counts. Used is set below.
@gotit movelong [BlockHand2],BlockPtr2
MoveWord newmax,[BlockPtr2]
; At this point we can assume that BlockHand2 can contain the given paragraph. Move all the text
; for the paragraph before where we want the gap into our new text block.
GotRoom addlong [BlockHand2],#W_BHeader,LastParPtr
rcall W_GetAddr,in=(par:a,#0:x)
phx ; src high
pha ; src low
pushlong LastParPtr
pushword #0 ; high, never moving more than 64k
pushword offset
_BlockMove ; mem move
; Get the total number of bytes that existed in the paragraph before growing it. Move text up
; to create the gap.
subword addbytes,bytes,addbytes
rcall W_GetAddr,in=(par:a,offset:x)
phx ; src high
pha ; src low
addword bytes,offset,a
addwl a,LastParPtr
pushlong LastParPtr
pushword #0 ; high, never moving more than 64k
subword addbytes,offset,s
_BlockMove ; mem move
; Update used counts for both original text block and new text block. Subtract the total number of
; bytes in the paragraph from the first block used count and add bytes grown to second block count.
; Replace text block for paragraph with the new one we have created. Exit with no errors.
movelong [ParPtr],BlockHand
movelong [BlockHand],BlockPtr
movelong [BlockHand2],BlockPtr2
ldy #W_BUsed
subword [BlockPtr]:y,addbytes,[BlockPtr]:y
addword bytes,addbytes,a
addword a,[BlockPtr2]:y,[BlockPtr2]:y
movelong BlockHand2,[ParPtr]
moveword #W_BHeader,[ParPtr]:#W_pOffset
brl exit
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; CASE 3: Paragraph is not last to use text block.
;
; In this case we need to put all the paragraphs after this one in their own block and then call
; MakeRoom to make this paragraph as big as we can.
; Get pointers to last document paragraph and next paragraph.
NotLast rcall W_GetParRec,in=(W_LastP:a),out=(LastParPtr:ax)
lda par
inc a
sta CurPar
jsl W_GetParRec
movelong ax,ParPtr
movelong ax,ParPtr2
; Get amount of space taken up by all latter paragraphs that share the same text block. Then find
; the last paragraph that shares the same text block with the paragraph we're trying to grow. If
; all remaining paragraphs in the document share this text block then we will need to create a
; brand new text block.
subword [BlockPtr]:#W_BUsed,[ParPtr]:#W_pOffset,addbytes
@loop cmpl [ParPtr2],BlockHand
bne GotIt
inc CurPar
addwl #W_pBytes,ParPtr2
cmpl LastParPtr,ParPtr2
bcs @loop
brl MakeNewOne2
; ParPtr2 now points to first paragraph with a different text block. Get its text block pointer.
GotIt movelong [ParPtr2],BlockHand2
movelong [BlockHand2],BlockPtr2
; Check if the text block can contain the latter paragraphs. If not we will need to create a brand
; new text block to hold them.
addword addbytes,[BlockPtr2]:#W_BUsed,a
cmpw a,[BlockPtr2]:#W_BSize
jcs MakeNewOne2
; Enough memory exists in the next text block to hold the paragraphs we are bumping. So move the next
; text blocks contents to make room for inserting the text we are bumping.
lda Curpar
ldx #0
jsl W_GetAddr
phx ; src high
pha ; src low
phx ; dest high
clc
adc addbytes
pha ; dest low
bcc @noinc
inx
txa
sta 3,s
@noinc pea 0 ; length high word - never more than 64k
subword [BlockPtr2]:#W_BUsed,#W_BHeader,s
_BlockMove ; mem move
; Update all the pointers for the paragraphs which reference the text block we just made a gap in.
; ParPtr2 initially points to curpars text block.
rcall W_GetParRec,in=(W_LastP:a),out=(LastParPtr:ax)
@loop cmpl [ParPtr2],BlockHand2
jne GotRoom2
ldy #W_pOffset
addword [ParPtr2]:y,addbytes,[ParPtr2]:y
addwl #W_pBytes,ParPtr2
cmpl LastParPtr,ParPtr2
bcs @loop
bra GotRoom2
; Need to create a new text block to hold the paragraphs that come after the one that we are trying
; to place a gap in (so it will have the text block to itself). If we get memory error then return
; it to the caller.
MakeNewOne2 movelong BlockHand, W_CurrentBlockHandle
stzl W_CurrentBlockHandle2
call W_MakeEmptyBlock,out=(BlockHand2:l)
jcs domemerr
; If we need more than 4k then we have to resize the empty block we just got. If resize fails or
; will generate a >64k text block then return with memory error. Note: don't want out of memory
; queue trying to shrink the handle we're trying to grow! If we can't resize the block make sure
; we dispose of it.
cmpw addbytes,#W_StartBlockSize
bcc GotRoom2
movelong BlockHand2,W_CurrentBlockHandle
addword addbytes,#W_GrowAmount,a
bcs @killblock2
@growit pea 0
pha
pushlong BlockHand2
jsl D_GrowHandle
bcc @gotit
@killblock2 tool _DisposeHandle,in=(BlockHand2:l)
brl domemerr
; Successfully resized the block - set its used and max counts.
@gotit movelong [BlockHand2],BlockPtr2
moveword addbytes,[BlockPtr2]:#W_BUsed
addword a,#W_GrowAmount,[BlockPtr2]
; We can assume at this point that BlockHand2 can contain the paragraphs after par. Move the text for
; these paragraphs into BlockHand2. Addbytes = amount of text that needs to be moved.
GotRoom2 lda par
inc a
jsl W_GetParRec
movelong ax,ParPtr
movelong [ParPtr],BlockHand
movelong [BlockHand],BlockPtr
addlong [BlockHand2],#W_BHeader,LastParPtr
lda par
inc a
ldx #0
jsl W_GetAddr
phx ; src high
pha ; src low
pushlong LastParPtr
pushword #0 ; high, never moving more than 64k
pushword addbytes
_BlockMove ; mem move
; Remove bytes from original text block used count and add to BlockHand2 used count.
movelong [Blockhand2],BlockPtr2
ldy #W_BUsed
subword [BlockPtr]:y,addbytes,[BlockPtr]:y
addword [BlockPtr2]:y,addbytes,[BlockPtr2]:y
; Get pointer to first paragraph that differed in text block ( or past last paragraph in document ).
; Get negative offset for paragraph's into new text block. For all paragraphs that came after par
; originally and are now in their own text block update their offsets. We have successfully
; split the block - now try to grow par's text block to the correct size.
rcall W_GetParRec,in=(CurPar:a),out=(LastParPtr:ax)
subword #W_BHeader,[ParPtr]:#W_pOffset,addbytes
@loop ldy #W_pOffset
addword [ParPtr]:y,addbytes,[ParPtr]:y
movelong BlockHand2,[ParPtr]
addwl #W_pBytes,ParPtr
cmpl ParPtr,LastParPtr
bcc @loop
brl TryAgain
domemerr moveword #$201,err
exit stzl W_CurrentBlockHandle
stzl W_CurrentBlockHandle2
return
W_CurrentBlockHandle DS.L 1
W_CurrentBlockHandle2 DS.L 1
ENDP
*****************************************************************************************************
; W_LessRoom ( Paragraph:word, Offset:word, Bytes:word )
;
; This routine is called to remove the given number of bytes at the given offset in the given
; paragraph's text block.
;
; Note: Always returns with no error (carry clear).
W_LessRoom PROC EXPORT
;Using wpglobals
;Using W_ParData
input par:w,offset:w,bytes:w
local BlockPtr:l,BlockHand:l,newsize:w,ParPtr:l,LastParPtr:l
local used:w,temp:l,ParOffset:w
error err
begin
; Deleting text so set file changed status. Get pointer to text block for paragraph.
stz err
call D_SetFileChanged,in=(W_CurDoc:l)
rcall W_GetParRec,in=(par:a),out=(ParPtr:ax)
movelong [ParPtr],BlockHand
moveword [ParPtr]:#W_pOffset,ParOffset
movelong [BlockHand],BlockPtr
; Subtract bytes from used count for text block.
ldy #W_BUsed
lda [BlockPtr],y
sta used
sec
sbc bytes
sta newsize
rcall W_GetAddr,in=(par:a,offset:x),out=(temp:ax)
clc
adc bytes
bcc @noinc
inx
@noinc phx ; source
pha
pushlong temp ; dest
pushword #0 ; high, never moving more than 64k
lda used
sec
sbc offset
sbc bytes
sbc ParOffset
pha
_BlockMove ; mem move
; Update used count in text block.
moveword newsize,[BlockPtr]:#W_BUsed
; Update all paragraph offsets for latter paragraphs that share the same text block.
rcall W_GetParRec,in=(W_LastP:a),out=(LastParPtr:ax)
bra @check
@loop cmpl [ParPtr],BlockHand
bne @endloop
ldy #W_pOffset
subword [ParPtr]:y,bytes,[ParPtr]:y
@check addwl #W_pBytes,ParPtr
cmpl LastParPtr,ParPtr
bcs @loop
@endloop
exit return
ENDP
*****************************************************************************************************
; W_NewRuler ( ): RulerHandle:long
;
; This routine is called to allocate a new standard ruler and initialize its used count to zero.
;
; Note: can return memory errors.
W_NewRuler PROC EXPORT
;Using W_RulerData
;Using WPGlobals
output DogRuler:l
local ptr:l
error err
begin
call D_NeedHand,in=(#W_RulBytes:l),out=(DogRuler:l),err=err
bcs @exit
tool _PtrToHand,in=(#StdRuler:l,DogRuler:l,#W_RulBytes:l)
movelong [DogRuler],ptr
moveword #0,[ptr]
@exit return
ENDP
*****************************************************************************************************
; W_ReadRuler ( RulerHandle:ax )
;
; This routine is called to move the given ruler's information into the WP current ruler globals.
W_ReadRuler PROC EXPORT
;Using WPGlobals
tool _HandToPtr,in=(ax:l,#W_WPRuler:l,#W_RulBytes:l)
rtl
ENDP
*****************************************************************************************************
; W_ReadRulerP ( ParagraphPtr:ax )
;
; This routine is called to move the given paragraph's ruler information into the WP current
; ruler globals.
W_ReadRulerP PROC EXPORT
;Using D_GlobalData
;Using WPGlobals
ParRec equ 0
tay
phd
lda >D_MainZPage
tcd
sty ParRec
stx ParRec+2
ldy #W_pRulerHand+2
lda [ParRec],y
tax
ldy #W_pRulerHand
lda [ParRec],y
jsl W_ReadRuler
pld
rtl
ENDP
*****************************************************************************************************
; W_UseRuler ( Count:word, RulerHand:long )
;
; This routine is called to increment the ruler's used count. This routine should be called
; whenever a paragraph is using the ruler.
W_UseRuler PROC EXPORT
input times:w,ruler:l
local ptr:l
begin
movelong [ruler],ptr
addword times,[ptr],[ptr]
return
ENDP
*****************************************************************************************************
; W_UnUseRuler ( Count:word, RulerHand:long )
;
; This routine is called to decrement the ruler's used count. This routine should be called
; whenever a paragraph is no longer using a ruler.
W_UnUseRuler PROC EXPORT
input times:w,ruler:l
local ptr:l
begin
movelong [ruler],ptr
subword [ptr],times,[ptr]
beq @killit
bpl @exit
@killit tool _DisposeHandle,in=(ruler:l)
@exit return
ENDP
*****************************************************************************************************
; W_FindLine ( Paragraph:word, Offset:word ): Line:word
;
; This routine is called to return the line in the paragraph corresponding to the given offset
; into the paragraph.
W_FindLine PROC EXPORT
input par:w,offset:w
local handle:l,ptr:l,ParRec:l,LinePtr:l,Ptr2:l
output line:w
begin
; Get line handle for paragraph. If no line handle exits then create valid line handles for the
; paragraph. If we can't make lines for paragraph then return with line set to last line and hope
; it's good enough.
rcall W_GetParRec,in=(par:a),out=(ParRec:ax)
movelong [ParRec]:#W_pLineHand,handle
cpzl handle
bne @notNIL
@makelines call W_ValidLines,in=(par:w)
bcc @gotlines
moveword [ParRec]:#W_pLastLine,line
dec line
brl exit
; If line handle has been purged then try to make lines.
@gotlines movelong [ParRec]:#W_pLineHand,handle
@notNIL movelong [handle],ptr
cpzl ptr
beq @makelines
; Loop through all lines for the paragraph comparing the given offset against them to determine in
; which line the offset falls.
stz line
@loop inc line
rcall W_GetLineRec,in=(ptr:ax,line:y),out=(lineptr:ax)
cmpw offset,[LinePtr]:#W_lOffset
beq @checktab
bcs @loop
bra @foundline
@checktab rcall W_GetAddr,in=(par:a,offset:x),out=(ptr2:ax)
cmpb [Ptr2],#9
bne @loop
@foundline dec line
cmpw [ParRec]:#W_pLastLine,line
beq @skip2
bcs exit
@skip2 dec a
sta line
exit return
ENDP
*****************************************************************************************************
; W_MakeCR ( Paragraph:word, Line:word, Offset:word )
;
; This routine is called to add a carriage return at the given offset in the given paragraph/line.
; This will create a new paragraph. The method used to insert the paragraph is as follows:
;
; 1. Get current font information
; 2. MakeRoom in paragraph at the given offset to insert a new text header + 1 carriage return char.
; 3. Put the current font information into the gap we made.
; 4. Make a new paragraph entry after the given paragraph.
; 5. Setup the new paragraph's offset.
; 6. MakeLines for both new paragraphs.
;
; Note: This routine can return memory errors.
W_MakeCr PROC EXPORT
;Using wpglobals
;Using W_ParData
input par:w,line:w,offset:w
local font:w,style:w,color:w,ptr:l,ParRec:l
local ParRec2:l
error err
begin
; Determine current font information at place we want to insert CR. Make room for new carriage return
; and text header in text block. If memory error then exit with error.
call W_FindFont,in=(par:w,line:w,offset:w),out=(style:w,font:w,color:w)
call W_MakeRoom,in=(par:w,offset:w,#W_TextHeader+1:w),err=err
bcs @goexit
; Made the gap. Now want to make sure we will be able to grow the paragraph array. Try to create new
; paragraph entry. If we can't then remove the gap and return with a memory error.
call W_MakeNewParRec,in=(par:w),err=err
bcc @gotpar
call W_LessRoom,in=(par:w,offset:w,#W_TextHeader+1:w)
@goexit brl exit
; Now get pointer to where we want CR and text header to start. Insert CR and text header.
@gotpar rcall W_GetAddr,in=(par:a,offset:x),out=(ptr:ax)
moveword #cr,[ptr]
moveword font,[ptr]:#1
moveword style,[ptr]:#3
moveword color,[ptr]:#5
; Get pointers to par and new par we added.
rcall W_GetParRec,in=(par:a),out=(ParRec:ax)
lda par
inc a
jsl W_GetParRec
movelong ax,ParRec2
; New paragraph's offset is going to be 1 past the CR we inserted @ offset in par.
moveword [ParRec]:#W_pOffset,a
sec ; inc 1 past the cr
adc offset
sta [ParRec2],y
; Make lines for old and new paragraphs.
call W_MakeLines,in=(par:w)
lda par
inc a
pha
jsl W_MakeLines
exit return
ENDP
*****************************************************************************************************
; W_MakeNewParRec ( Paragraph:word )
;
; This routine is called to create a new paragraph record in the paragraph array - after the given
; paragraph. The new paragraph entry is initialized as follows:
;
; TextBlock - same as Paragraph
; offset - ???
; Attr - 0
; RulerHandle - same as Paragraph
; Pixels - 0
; LineHandle - NIL
; LastLine - 0
;
; Note: Memory errors are returned!
W_MakeNewParRec PROC EXPORT
;Using wpglobals
ParIncment equ 10
input par:w
local Src:l,Dest:l,Length:l,NewMax:w,NewSize:l
error err
begin
; Check if paragraph array has enough room to just add entry. If not try to grow paragraph array to
; new size. If memory error then exit with error globals intact; else update W_MaxP.
stz err
cmpw W_LastP,W_MaxP
bcc @hasroom
adc #ParIncment-1
sta NewMax
tool _Multiply,in=(NewMax:w,#W_pBytes:w),out=(NewSize:l)
call D_GrowLHandle,in=(NewSize:l,W_PHandle:l),out=(W_PPtr:l),err=err
jcs exit
moveword NewMax,W_MaxP
; Enough room now exists in paragraph array handle to add extra paragraph entry. Get pointers to
; par and par+1. Copy par through last par contents up one paragraph entry.
@hasroom rcall W_GetParRec,in=(par:a),out=(src:ax)
lda par
inc a
jsl W_GetParRec
movelong ax,Dest
inc W_LastP
rcall W_GetParRec,in=(W_LastP:a),out=(length:ax)
cmpw par,W_LastP
beq @nomove
pushlong Src
pushlong Dest
sublong Length,Src,s
_BlockMove
; Initialize other fields of new paragraph record. Note: TextBlock and RulerHandles will have been
; inherited by the copy.
@nomove lda #0
moveword a,[Dest]:#W_pAttr
moveword a,[Dest]:#W_pLastLine
moveword a,[Dest]:#W_pPixels
moveword a,[Dest]:#W_pLineHand
moveword a,[Dest]:#W_pLineHand+2
call W_UseRuler,in=(#1:w,[Dest]:#W_pRulerHand:l)
exit return
ENDP
*****************************************************************************************************
; W_ParLock ( Paragraph:word )
;
; This routine is called to lock the text block and line handles for the given paragraph.
W_ParLock PROC EXPORT
input par:w
local ParRec:l
begin
rcall W_GetParRec,in=(par:a),out=(ParRec:ax)
tool _HLock,in=([ParRec]:#W_pBlockHand:l)
tool _HLock,in=([ParRec]:#W_pLineHand:l)
return
ENDP
*****************************************************************************************************
; W_ParUnLock ( Paragraph:word )
;
; This routine is called to unlock the text block and line handles for the given paragraph.
W_ParUnLock PROC EXPORT
input par:w
local ParRec:l
begin
rcall W_GetParRec,in=(par:a),out=(ParRec:ax)
tool _HUnLock,in=([ParRec]:#W_pBlockHand:l)
tool _HUnLock,in=([ParRec]:#W_pLineHand:l)
return
ENDP
*****************************************************************************************************
; W_GetLastLine ( Paragraph:a ):Line:a
;
; This routine is called to return the last line for the given paragraph.
W_GetLastLine PROC EXPORT
pha
pha
pha
jsl W_GetLastLGuts
plx
pla
rtl
ENDP
*****************************************************************************************************
; W_GetLastLGuts ( Paragraph:word ): Line:word, Offset:word
;
; This routine is called to return the last line for the given paragraph and its offset in the
; paragraph's text block.
W_GetLastLGuts PROC EXPORT
;Using wpglobals
;Using D_GlobalData
input par:w
output line:w,offset:w
local ptr:l,LinePtr:l
begin
rcall W_GetParRec,in=(Par:a),out=(Ptr:ax)
moveword [ptr]:#W_pLastLine,line
call W_GetLRecPtr,in=(par:w,line:w),out=(lineptr:l)
moveword [LinePtr]:#W_lOffset,offset
dec line
return
ENDP
*****************************************************************************************************
; W_GetEndPar ( Paragraph:word ): Bytes:word
;
; This routine is called to return the number of bytes in the given paragraph.
W_GetEndPar PROC EXPORT
;Using wpglobals
input par:w
local ParRec:l,Block:l,ptr:l
output bytes:w
begin
rcall W_GetParRec,in=(par:a),out=(parrec:ax)
movelong [ParRec],Block
movelong [Block],ptr
moveword [ptr]:#W_BUsed,bytes
cmpw par,W_LastP
bcs @GotBytes
cmpl [ParRec],[ParRec]:#W_pBytes
bne @GotBytes
moveword [ParRec]:#W_pOffset+W_pBytes,bytes
@GotBytes subword bytes,[ParRec]:#W_pOffset,bytes
dec bytes
return
ENDP
*****************************************************************************************************
; W_DelPars ( Par1:word, Par2:word )
;
; This routine is called to delete the range of paragraphs between 1 & 2 inclusive.
W_DelPars PROC EXPORT
;Using wpglobals
input par1:w,par2:w
local EndPtr:l,EP1Ptr:l,bytes:l,Pm1Ptr:l,CurPar:l,BPtr:l
local FirstBlock:l,LastBlock:l,OldBlock:l,ParRec:l
local ptr:l,BegOffset:w,EndOffset:w,LastParPtr:l
begin
; Lock down paragraph array handle and get pointer to its end.
rcall D_Deref,in=(W_PHandle:ax)
lda W_LastP
inc a
jsl W_GetParRec
movelong ax,EndPtr
; Get pointers to paragraph before par1 and paragraph after par2.
lda par1
dec a
jsl W_GetParRec
movelong ax,Pm1Ptr
lda par2
inc a
jsl W_GetParRec
movelong ax,EP1Ptr
; Initialize first and last text blocks for loop.
movelong [Pm1Ptr],FirstBlock
stzl LastBlock
cmpw W_LastP,par2
beq @GotLast
movelong [EP1Ptr],LastBlock
@GotLast moveword par1,CurPar
stzl OldBlock
PLoop rcall W_GetParRec,in=(CurPar:a),out=(ParRec:ax)
cmpw [ParRec]:#W_pAttr,#W_PgBrk
beq NextPar
call W_UnUseRuler,in=(#1:w,[ParRec]:#W_pRulerHand:l)
cpzl [ParRec]:#W_pLineHand
beq NoKill
tool _DisposeHandle,in=([ParRec]:#W_pLineHand:l)
NoKill cmpl [ParRec],OldBlock
beq NextPar
movelong [ParRec],OldBlock
cmpl OldBlock,FirstBlock
beq NextPar
cmpl OldBlock,LastBlock
beq NextPar
tool _DisposeHandle,in=(OldBlock:l)
NextPar inc CurPar
cmpw par2,CurPar
jge PLoop
; now am done with all the in between pars, work on extremes
movelong [FirstBlock],BPtr
cmpl FirstBlock,LastBlock
bne NotSame
moveword [EP1Ptr]:#W_pOffset,EndOffset
moveword [PM1Ptr]:#W_pBytes+W_pOffset,BegOffset
bra GotBOffset
NotSame cmpl [PM1Ptr],[PM1Ptr]:#W_pBytes
bne NoZap
moveword [PM1Ptr]:#W_pBytes+W_pOffset,[BPtr]:#W_BUsed
NoZap moveword #W_BHeader,BegOffset
cpzl LastBlock
jeq NoMove
rcall W_GetParRec,in=(par2:a),out=(parrec:ax)
cmpl [ParRec],[EP1Ptr]
jne DoArray
movelong [LastBlock],BPtr
moveword [EP1Ptr]:#W_pOffset,EndOffset
GotBOffset ldx BPtr+2
addword EndOffset,Bptr,a
bcc NoIx
inx
NoIX phx
pha
ldx BPtr+2
addword BegOffset,Bptr,a
bcc NoIx2
inx
NoIX2 phx
pha
pushword #0
subword [Bptr]:#W_BUsed,EndOffset,s
_BlockMove
subword EndOffset,BegOffset,bytes
subword [BPtr]:#W_BUsed,bytes,[BPtr]:#W_BUsed
movelong EP1Ptr,ParRec
; Now update all relevant ptrs.
rcall W_GetParRec,in=(W_LastP:a),out=(LastParPtr:ax)
bra @check
@loop cmpl [ParRec],LastBlock
bne @endloop
ldy #W_pOffset
subword [ParRec]:y,bytes,[ParRec]:y
addwl #W_pBytes,ParRec
@check cmpl LastParPtr,ParRec
bge @loop
@endloop
; Now adjust the par array
DoArray sublong EndPtr,EP1Ptr,bytes
pushlong EP1Ptr
lda par1
jsl W_GetParRec
phx
pha
pushlong bytes
_BlockMove
; W_LastP - (par2-par1+1)
NoMove lda W_LastP
clc
sbc par2
clc
adc par1
sta W_LastP
return
ENDP
*****************************************************************************************************
; W_CheckWidow ( Paragraph:a )
;
; This routine is called to check if the given paragraph can be widowed or not. The carry will be
; set on return if widow is set in the ruler bits of the paragraph's ruler.
W_CheckWidow PROC EXPORT
;Using wpglobals
;Using D_GlobalData
handle equ 0
ptr equ 4
tay
phd
lda >D_MainZPage
tcd
clc
lda W_Stuff
bne @exit
tya
jsl W_GetParRec
jsl W_ReadRulerP
lda W_RulBits
and #W_r_widow
clc
beq @exit
sec
@exit pld
rtl
ENDP
END