***************************************************************************************************** ; 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