mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-12-01 02:51:04 +00:00
775 lines
27 KiB
Plaintext
775 lines
27 KiB
Plaintext
;
|
|
; File: ScriptMgrTruncRepl.a
|
|
;
|
|
; Contains: New routines for text truncation and replacement.
|
|
;
|
|
; Written by: PKE Peter Edberg
|
|
;
|
|
; Copyright: © 1989-1992 by Apple Computer, Inc. All rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM3> 11/6/92 SWC Changed PackMacs.a->Packages.a.
|
|
; <3> 4/30/92 FM Get rid of conditional smgrSys7Extensions
|
|
; <2> 5/18/90 PKE Adapt to new changes in 'itl4' resource: get truncation marker
|
|
; for TruncText from unToken table instead of special truncMarker
|
|
; table.
|
|
; <1> 4/10/90 PKE New today - extracted from ScriptMgrExtTail.a and
|
|
; conditionalized so it can be used with ROM builds too.
|
|
;
|
|
; Relevant recent comments from ScriptMgrExtTail.a below
|
|
; <x7> 3/5/90 PKE In TruncString/TruncText, changed NTruncX selectors to TruncX.
|
|
; <x6> 3/2/90 PKE Use new name nItl4Rec for 7.0 extended version of Itl4Rec.
|
|
; <1.7> 11/8/89 PKE Modify TruncString and TruncText to support both new and old
|
|
; calling conventions (with and without truncWhere parameter).
|
|
; Implement handling of center truncation (in TruncText).
|
|
; <1.4> 9/17/89 PKE Better error reporting in TruncText, ReplaceText.
|
|
; <1.3> 9/15/89 PKE Add and install framework code for TruncString, TruncText,
|
|
; ReplaceText. Stuff correct version number in SMgrRecord.
|
|
;
|
|
|
|
LOAD 'StandardEqu.d'
|
|
include 'ScriptPriv.a'
|
|
include 'Packages.a'
|
|
|
|
blanks on
|
|
string asis
|
|
|
|
; ----------------------------------------------------------------------- <1.3>
|
|
; TruncString and TruncText routines.
|
|
;
|
|
; TruncCode = Integer;
|
|
;
|
|
; FUNCTION TruncString(width: Integer; VAR theString: Str255;
|
|
; truncWhere: TruncCode): Integer;
|
|
;
|
|
; FUNCTION TruncText(width: Integer; textPtr: Ptr; VAR length: Integer;
|
|
; truncWhere: TruncCode): Integer;
|
|
;
|
|
; These routines will ensure that a text string fits into the pixel length
|
|
; specified by width, truncating the string if necessary in a way that depends
|
|
; on the script associated with the font of the current grafPort. This includes
|
|
; proper handling of double-byte characters and insertion of a truncation
|
|
; indicator (such as an ellipsis in English). The truncation indicator is
|
|
; obtained from a string in the current script's 'itl4' resource. In the first
|
|
; form (TruncString), the string is supplied as a Str255. In the second form
|
|
; of the call (TruncText), the string is defined by a pointer and byte length;
|
|
; the length will be updated if necessary. In either form, the length will
|
|
; not increase. The truncWhere argument is a constant specifying where
|
|
; where truncation should occur. At present, only two values are defined:
|
|
; smTruncEnd (0) and smTruncMiddle ($4000, although any non-zero value will
|
|
; currently work).
|
|
;
|
|
; Result codes:
|
|
; 0 No truncation was necessary.
|
|
; 1 Truncation was performed.
|
|
; (negative=>error:)
|
|
; -1 General error: truncation is necessary, but the truncation
|
|
; indicator is too big - longer than the length parameter or
|
|
; wider than the width parameter. In this case, the returned
|
|
; length will be 0.
|
|
; resNotFound Can't get itl4 resource, or it's not in current format
|
|
;
|
|
; Note that TruncString is basically just glue that converts a Str255 to
|
|
; pointer and length, calls TruncText, and then converts back again.
|
|
;
|
|
; Also note that we are still supporting an older form of each call, without
|
|
; the truncWhere parameter. We can tell from the selector which form we were
|
|
; called with. For the old form, we truncate at the end.
|
|
; -----------------------------------------------------------------------------
|
|
|
|
proc
|
|
import StdUnlink
|
|
export TruncString,TruncText ; <1>
|
|
|
|
; --------------------------------------
|
|
; TruncString
|
|
|
|
; stack setup at entry for old-style call:
|
|
;
|
|
; (high address)
|
|
; result ds.w 1 ; result code
|
|
; width ds.w 1 ; width for truncated text.
|
|
; theString ds.l 1 ; pointer to Str255 to be truncated
|
|
; selector ds.l 1 ; selector
|
|
; return ds.l 1 ; return address.
|
|
; (low address)
|
|
;
|
|
; stack frame for new-style call:
|
|
|
|
ntsRecord record {a6link},decr ; <1.7>
|
|
result ds.w 1 ; result code
|
|
ntsArgs equ *-8 ; size of arguments.
|
|
width ds.w 1 ; width for truncated text.
|
|
theString ds.l 1 ; pointer to Str255 to be truncated
|
|
truncWhere ds.w 1 ; truncation location code <1.7>
|
|
selector ds.l 1 ; selector
|
|
return ds.l 1 ; return address.
|
|
a6link ds.l 1 ; old a6 register.
|
|
lenWord ds.w 1 ; word-size length to modify
|
|
ntsLocals equ * ; size of local variables.
|
|
endr
|
|
|
|
TruncString ; <1>
|
|
; If this is an old-style TruncString call, fake a new-style call with the
|
|
; truncWhere parameter set up to truncate at the end, which is what the <1.7>
|
|
; old call did.
|
|
|
|
move.l 4(sp),d0 ; get selector
|
|
cmp.l #smSelTruncString,d0 ; is it the new form?
|
|
beq.s nTruncString ; if yes, no stack tweaking
|
|
|
|
move.l (sp)+,d1 ; pop return addr
|
|
addq.l #4,sp ; kill selector on stack; it's in d0
|
|
move.w #smTruncEnd,-(sp) ; add TruncWhere parameter
|
|
move.l d0,-(sp) ; push selector again
|
|
move.l d1,-(sp) ; push return address again
|
|
|
|
; now we are set up like a call to the new TruncString
|
|
|
|
nTruncString ; <1.7>
|
|
with ntsRecord ; <1.7>
|
|
link a6,#ntsLocals ; link the stack. <1.7>
|
|
|
|
move.l theString(a6),a0 ; get theString
|
|
clr.w d0 ; for wordizing
|
|
move.b (a0)+,d0 ; get length, make text pointer
|
|
move.w d0,lenWord(a6) ; word-size length to modify
|
|
|
|
subq #2,sp ; allocate space for TruncText result
|
|
move.w width(a6),-(sp) ; push width
|
|
move.l a0,-(sp) ; push textPtr
|
|
pea lenWord(a6) ; push addr of length
|
|
move.w truncWhere(a6),-(sp) ; push truncWhere <1.7>
|
|
move.l #smSelTruncText,-(sp) ; now it's a new TruncText call <1.7>
|
|
bsr.s nTruncText ; <1.7>
|
|
move.w (sp)+,result(a6) ; result code
|
|
|
|
move.w lenWord(a6),d0 ; new length
|
|
move.l theString(a6),a0 ; get addr of Str255
|
|
move.b d0,(a0) ; update length
|
|
|
|
move.w #ntsArgs,d0 ; set up for StdUnlink <1.7>
|
|
bra StdUnlink
|
|
endwith
|
|
|
|
; --------------------------------------
|
|
; TruncText
|
|
|
|
; stack setup at entry for old-style call:
|
|
;
|
|
; (high address)
|
|
; result ds.w 1 ; result code
|
|
; width ds.w 1 ; width for truncated text.
|
|
; textPtr ds.l 1 ; pointer to text to be truncated
|
|
; lengthPtr ds.l 1 ; pointer to length of text (VAR)
|
|
; selector ds.l 1 ; selector
|
|
; return ds.l 1 ; return address.
|
|
; (low address)
|
|
;
|
|
; stack frame for new-style call:
|
|
|
|
nttRecord record {a6link},decr ; <1.7>
|
|
result ds.w 1 ; result code
|
|
nttArgs equ *-8 ; size of arguments.
|
|
width ds.w 1 ; width for truncated text.
|
|
textPtr ds.l 1 ; pointer to text to be truncated
|
|
lengthPtr ds.l 1 ; pointer to length of text (VAR)
|
|
truncWhere ds.w 1 ; truncation location code <1.7>
|
|
selector ds.l 1 ; selector
|
|
return ds.l 1 ; return address.
|
|
a6link ds.l 1 ; old a6 register.
|
|
headWidth ds.w 1 ; current width for head string <1.7>
|
|
tailWidth ds.w 1 ; current width for tail string <1.7>
|
|
nttLocals equ * ; size of local variables.
|
|
endr
|
|
|
|
; register usage:
|
|
; a4 length ptr
|
|
; a3 SMgrRecord ptr/trunc marker ptr
|
|
; a2 textPtr
|
|
; d7 length of trunc marker (bytes)
|
|
; d6 current length of truncated string without marker (bytes)
|
|
; d5 desired width less trunc marker width
|
|
; d4 size of space for trunc marker on stack <1.7>
|
|
; d3 length of text (bytes)
|
|
;
|
|
|
|
TruncText ; <1>
|
|
; If this is an old-style TruncText call, fake a new-style call with the
|
|
; truncWhere parameter set up to truncate at the end, which is what the <1.7>
|
|
; old call did.
|
|
|
|
move.l 4(sp),d0 ; get selector
|
|
cmp.l #smSelTruncText,d0 ; is it the new form?
|
|
beq.s nTruncText ; if yes, no stack tweaking
|
|
|
|
move.l (sp)+,d1 ; pop return addr
|
|
addq.l #4,sp ; kill selector on stack; it's in d0
|
|
move.w #smTruncEnd,-(sp) ; add TruncWhere parameter
|
|
move.l d0,-(sp) ; push selector again
|
|
move.l d1,-(sp) ; push return address again
|
|
|
|
; now we are set up like a call to the new TruncString
|
|
|
|
nTruncText ; <1.7>
|
|
with nttRecord ; <1.7>
|
|
link a6,#nttLocals ; link the stack.
|
|
movem.l a2-a4/d3-d7,-(sp) ; save registers
|
|
clr.w result(a6) ; initially assume no truncation, no err
|
|
|
|
; Get text, see if it already fits in width
|
|
move.l textPtr(a6),a2 ; save textPtr in a2
|
|
move.l lengthPtr(a6),a4 ; pointer to length
|
|
move.w (a4),d3 ; save length of text
|
|
subq #2,sp ; allocate space for TextWidth return
|
|
move.l a2,-(sp) ; push pointer to text
|
|
clr.w -(sp) ; first byte is 0
|
|
move.w d3,-(sp) ; push length of text
|
|
_TextWidth
|
|
move.w (sp)+,d0 ; get text width
|
|
cmp.w width(a6),d0 ;
|
|
ble ttExit ; if already ok, we're done
|
|
|
|
; Get truncMarker from itl4
|
|
with SMgrRecord,nItl4Rec ; <x6>
|
|
move.w #resNotFound,result(a6) ; now assume bad itl4
|
|
GetSMgrCore a3 ; get pointer to SMgrRecord
|
|
move.b smgrIntlForce(a3),-(sp) ; save IntlForce
|
|
clr.b smgrIntlForce(a3) ; now clear it for GetIntl
|
|
clr.l -(sp) ; space for returned handle
|
|
move.w #4,-(sp) ; select itl4
|
|
_IUGetIntl ; may trash a0,a1,d0-d2
|
|
move.l (sp)+,a0 ; store itl4 handle
|
|
move.b (sp)+,smgrIntlForce(a3) ; restore IntlForce
|
|
move.l a0,d0 ; nil handle?
|
|
beq ttExit ; bail if so
|
|
move.l (a0),a0 ; dereference
|
|
move.l unTokenOffset(a0),d0 ; check offset <2>
|
|
beq ttExit ; if 0, bail <2>
|
|
add.l d0,a0 ; point to unToken table <2>
|
|
cmp.w #tokenEllipsis,2(a0) ; does it include ellipsis? <2>
|
|
blt ttExit ; if not, bail <2>
|
|
add.w 4+(2*tokenEllipsis)(a0),a0 ; point to ellipsis string <2>
|
|
endwith ;SMgrRecord,nItl4Rec ;
|
|
|
|
; check truncation marker length
|
|
move.w #-1,result(a6) ; now assume general error
|
|
clr.w (a4) ; and set length to 0 <1.7>
|
|
moveq #0,d7 ; for word/longizing
|
|
move.b (a0)+,d7 ; get byte length of trunc marker
|
|
move.w d3,d6 ; copy string length
|
|
sub.w d7,d6 ; subtract trunc marker length
|
|
blt ttExit ; bail if trunc marker longer than string
|
|
|
|
; copy trunc marker to stack (instead of to end of string as before) <1.7>
|
|
move.w d7,d4 ; copy marker length
|
|
addq.w #1,d4 ;
|
|
andi.w #$FFFE,d4 ; length is rounded up to even number
|
|
sub.w d4,sp ; allocate space on stack for marker
|
|
move.l sp,a3 ; save trunc marker pointer
|
|
move.l a3,a1 ; copy dest ptr (a0 is src ptr)
|
|
move.w d7,d0 ; copy trunc marker length
|
|
beq.s @noCopy ; skip copy if 0 <1.7>
|
|
subq.w #1,d0 ; for dbra
|
|
@1 move.b (a0)+,(a1)+ ; copy
|
|
dbra d0,@1 ;
|
|
@noCopy ; <1.7>
|
|
|
|
; subtract width of trunc marker from desired width; moved up here <1.7>
|
|
move.w width(a6),d5 ; get desired width
|
|
subq #2,sp ; allocate space for return value
|
|
move.l a3,-(sp) ; push pointer to trunc marker
|
|
clr.w -(sp) ; first byte is 0
|
|
move.w d7,-(sp) ; push length of trunc marker
|
|
_TextWidth
|
|
sub.w (sp)+,d5 ; subtract width of trunc marker
|
|
bmi ttCleanUp ; bail if trunc marker too wide -
|
|
; should we trunc without marker instead?
|
|
; select type of truncation
|
|
tst.w truncWhere(a6) ; where do we truncate? <1.7>
|
|
bne.s ttDoMiddle ; if not end, assume middle <1.7>
|
|
|
|
; --------------------------------------
|
|
; Truncate at end: while width of remaining text too big, subtract a char
|
|
; (NOT necessarily a byte!!).
|
|
|
|
;; bra.s @doTextWidth ; (no longer want this) <1.7>
|
|
addq.w #1,d6 ; compensate for initial decrement <1.7>
|
|
@loop
|
|
subq.w #1,d6 ; decrement current string count
|
|
bsr DoCharByteHead ; adjust d6 to char boundary <1.7>
|
|
bsr DoTextWidthHead ; put head width in d0.w <1.7>
|
|
cmp.w d0,d5 ; compare desired width to current
|
|
blt.s @loop
|
|
|
|
; move trunc marker to end of truncated string
|
|
lea 0(a2,d6.w),a1 ; dest ptr for trunc marker
|
|
move.w d7,d0 ; copy trunc marker length
|
|
beq.s @noMarker ; skip if 0 <1.7>
|
|
subq.w #1,d0 ; for dbra
|
|
@2 move.b (a3)+,(a1)+ ; copy
|
|
dbra d0,@2 ;
|
|
@noMarker ; <1.7>
|
|
|
|
; set length & result (eventually, do fancier stuff here like check to see
|
|
; if string + marker is too long and continue reducing length if so)
|
|
add.w d7,d6 ; total truncated length with marker
|
|
move.w d6,(a4) ; set new length
|
|
bra.s ttTruncOk ; all done, go clean up and exit <1.7>
|
|
|
|
; --------------------------------------
|
|
; Truncate in middle. Basically, we take the bytes remaining in the string
|
|
; after subtracting those needed for the truncMarker, divide them by two,
|
|
; and start with head and tail strings of this roughly this length (adjusted
|
|
; for character boundaries, etc.). While the sum of the widths of the head
|
|
; and tail strings is too big, we remove characters from one or the other of
|
|
; the strings (the head string if it is longer, otherwise the tail string).
|
|
|
|
ttDoMiddle
|
|
lsr.w #1,d6 ; half of remaining length for head
|
|
bsr DoCharByteHead ; adjust d6 to char boundary
|
|
|
|
move.l a2,a3 ; now make pointer to back half:
|
|
add.w d6,a3 ; advance past first half…
|
|
add.w d7,a3 ; …and trunc marker.
|
|
sub.w d6,d3 ; get length: subtract first half…
|
|
sub.w d7,d3 ; and trunc marker.
|
|
bsr DoCharByteTail ; adjust a3/d3 for char boundary
|
|
|
|
; Registers at this point:
|
|
; a4 length ptr
|
|
; a3 pointer to back string
|
|
; a2 pointer to front string
|
|
; d7 length of trunc marker (bytes)
|
|
; d6 current length of front string
|
|
; d5 desired width less trunc marker width
|
|
; d4 size of space for trunc marker on stack
|
|
; d3 current length of back string
|
|
|
|
bsr DoTextWidthHead ; put head width in d0.w
|
|
move.w d0,headWidth(a6) ; save head width
|
|
bsr DoTextWidthTail ; put tail width in d0.w
|
|
move.w d0,tailWidth(a6) ; save tail width
|
|
bra.s @loopTest
|
|
|
|
@loop
|
|
cmp.w d6,d3 ; who has more bytes: head or tail?
|
|
bge.s @shortenTail ; shorten tail if longer or same
|
|
|
|
@shortenHead
|
|
subq.w #1,d6
|
|
bsr DoCharByteHead ; adjust d6 to char boundary
|
|
bsr DoTextWidthHead ; put head width in d0.w
|
|
move.w d0,headWidth(a6) ; save head width
|
|
bra.s @loopTest
|
|
|
|
@shortenTail
|
|
subq.w #1,d3
|
|
addq #1,a3
|
|
bsr DoCharByteTail ; adjust a3/d3 for char boundary
|
|
bsr DoTextWidthTail ; put tail width in d0.w
|
|
move.w d0,tailWidth(a6) ; save tail width
|
|
|
|
@loopTest
|
|
move.w headWidth(a6),d0
|
|
add.w tailWidth(a6),d0
|
|
cmp.w d0,d5 ; compare desired width to current
|
|
blt.s @loop
|
|
|
|
; assemble string (note that sp points to trunc marker)
|
|
move.l sp,a0 ; reset trunc marker pointer
|
|
lea 0(a2,d6.w),a1 ; dest ptr for trunc marker
|
|
|
|
move.w d7,d0 ; copy trunc marker length
|
|
beq.s @noMarker ;
|
|
subq.w #1,d0 ; for dbra
|
|
@1 move.b (a0)+,(a1)+ ; copy
|
|
dbra d0,@1 ;
|
|
@noMarker
|
|
|
|
move.w d3,d0 ; copy tail string length
|
|
beq.s @noTail ;
|
|
subq.w #1,d0 ; for dbra
|
|
@2 move.b (a3)+,(a1)+ ; copy
|
|
dbra d0,@2 ;
|
|
@noTail
|
|
|
|
; set length & result (eventually, do fancier stuff here like check to see
|
|
; if string + marker is too long and continue reducing length if so)
|
|
add.w d7,d6 ; add trunc marker length to head length
|
|
add.w d3,d6 ; now add in tail length
|
|
move.w d6,(a4) ; set new length
|
|
|
|
; --------------------------------------
|
|
; clean up and return
|
|
ttTruncOk ; <1.7>
|
|
move.w #1,result(a6) ; we truncated it
|
|
ttCleanUp ; <1.7>
|
|
add.w d4,sp ; kill trunc marker space on stack <1.7>
|
|
ttExit
|
|
movem.l (sp)+,a2-a4/d3-d7 ; restore registers
|
|
move.w #nttArgs,d0 ; set up for StdUnlink <1.7>
|
|
bra StdUnlink
|
|
endwith
|
|
|
|
; --------------------------------------
|
|
; little subroutines for code savings:
|
|
|
|
; DoCharByteHead: a2 is pointer to text, d6.w is length; will decrement
|
|
; d6.w by one character (one or two bytes).
|
|
|
|
DoCharByteHead
|
|
subq #2,sp ; allocate space for CharByte return
|
|
move.l a2,-(sp) ; push text ptr
|
|
move.w d6,-(sp) ; push offset
|
|
_CharByte
|
|
tst.w (sp)+ ; are we at 2nd byte of 2-byte char?
|
|
ble.s @1 ; skip decrement if not
|
|
subq.w #1,d6 ; decrement length to char boundary
|
|
@1 rts
|
|
|
|
; DoCharByteTail: a3 is pointer to text, d3.w is length; will increment
|
|
; a3, and decrement d3.w, by one character (one or two bytes).
|
|
|
|
DoCharByteTail
|
|
subq #2,sp ; allocate space for CharByte return
|
|
move.l a3,-(sp) ; push text ptr
|
|
move.w d3,-(sp) ; push offset
|
|
_CharByte
|
|
tst.w (sp)+ ; are we at 2nd byte of 2-byte char?
|
|
ble.s @1 ; skip increment if not
|
|
addq #1,a3 ; advance to beginning of next char…
|
|
addq.w #1,d3 ; and update length.
|
|
@1 rts
|
|
|
|
; DoTextWidthHead: a2 is pointer to text, d6.w is length; will return
|
|
; TextWidth value in d0.w.
|
|
|
|
DoTextWidthHead
|
|
subq #2,sp ; allocate space for return value
|
|
move.l a2,-(sp) ; push pointer to text
|
|
clr.w -(sp) ; first byte is 0
|
|
move.w d6,-(sp) ; push remaining length of text
|
|
_TextWidth
|
|
move.w (sp)+,d0 ; save width
|
|
rts
|
|
|
|
; DoTextWidthTail: a3 is pointer to text, d3.w is length; will return
|
|
; TextWidth value in d0.w.
|
|
|
|
DoTextWidthTail
|
|
subq #2,sp ; allocate space for return value
|
|
move.l a3,-(sp) ; push pointer to text
|
|
clr.w -(sp) ; first byte is 0
|
|
move.w d3,-(sp) ; push remaining length of text
|
|
_TextWidth
|
|
move.w (sp)+,d0 ; save width
|
|
rts
|
|
|
|
endproc
|
|
|
|
|
|
; ----------------------------------------------------------------------- <1.3>
|
|
; ReplaceText routine.
|
|
;
|
|
; FUNCTION ReplaceText(baseText: Handle; substitutionText: Handle;
|
|
; key: Str15): Integer;
|
|
;
|
|
; The key parameter contains a string to be used as the substitution marker.
|
|
; The routine will search through the text indicated by baseText for instances
|
|
; of this string, and replace each instance with the text indicated by
|
|
; substitutionText. The contents of substitutionText will not affect the
|
|
; substitution process: the substitution text may contain the key string,
|
|
; which will be inserted verbatim into the base text.
|
|
;
|
|
; Result codes:
|
|
; 0 or positive Number of substitutions performed.
|
|
; (negative=>error:)
|
|
; nilHandleErr GetHandleSize fails on baseText or substitutionText
|
|
; memWZErr GetHandleSize fails on baseText or substitutionText
|
|
; memFullErr SetHandleSize fails on baseText
|
|
; -----------------------------------------------------------------------------
|
|
|
|
proc
|
|
import StdUnlink
|
|
export ReplaceText ; <1>
|
|
|
|
rtRecord record {a6link},decr
|
|
result ds.w 1 ; integer result
|
|
rtArgs equ *-8 ; size of arguments.
|
|
baseText ds.l 1 ; Handle for base text.
|
|
subsText ds.l 1 ; Handle for substitution text
|
|
key ds.l 1 ; pointer to Str15, substitution key
|
|
selector ds.l 1 ; selector
|
|
return ds.l 1 ; return address.
|
|
a6link ds.l 1 ; old a6 register.
|
|
rtLocals equ * ; size of local variables.
|
|
endr
|
|
|
|
; register usage:
|
|
; a4 baseText pointer
|
|
; a3 subsText pointer
|
|
; a2 key pointer
|
|
; d7 baseText length
|
|
; d6 subsText length - key length
|
|
; d5 key length
|
|
; d4 substitution count * (subsText length - key length)
|
|
; d3 substitution count
|
|
;
|
|
|
|
ReplaceText ; <1>
|
|
with SMgrRecord,rtRecord
|
|
link a6,#rtLocals ; link the stack.
|
|
movem.l a2-a4/d3-d7,-(sp) ; save registers
|
|
|
|
; get pointers and sizes
|
|
clr.w d0 ; assume no substitution
|
|
|
|
move.l key(a6),a2 ; pointer to Pascal string
|
|
moveq #0,d5 ; for longizing
|
|
move.b (a2)+,d5 ; key length, now a2 pts to key text
|
|
beq rtBail ; bail if no key
|
|
|
|
move.l baseText(a6),a4 ; baseText handle
|
|
move.l a4,a0 ; copy
|
|
_GetHandleSize
|
|
tst.l d0 ; need tst.l, not dispatcher's tst.w
|
|
bmi rtBail
|
|
move.l d0,d7 ; save baseText length
|
|
move.l (a4),a4 ; baseText ptr
|
|
|
|
move.l subsText(a6),a3 ; subsText handle
|
|
move.l a3,a0 ; copy
|
|
_GetHandleSize
|
|
tst.l d0 ; need tst.l, not dispatcher's tst.w
|
|
bmi rtBail
|
|
move.l d0,d6 ; subsText length
|
|
move.l (a3),a3 ; subsText ptr
|
|
|
|
sub.w d5,d6 ; subsText length - key length
|
|
|
|
; set up for search loop. Additional register usage:
|
|
; a1 working key pointer
|
|
; a0 working baseText pointer
|
|
; d2 last basetext offset at which to try match
|
|
; d1 working baseText offset
|
|
; d0 working key length count for dbne
|
|
;
|
|
|
|
moveq #0,d4 ; init accumulator
|
|
moveq #0,d3 ; init substitution count
|
|
moveq #0,d1 ; working offset in baseText
|
|
move.w d7,d2 ;
|
|
sub.w d5,d2 ; last start offset for key search
|
|
subq.w #1,d5 ; temporary fix for dbne
|
|
bra.s @loopProcess ; skip first increment
|
|
|
|
; outer loop, which increments position in baseText
|
|
@loopAdvance
|
|
addq.w #1,d1 ; next baseText offset
|
|
|
|
; make sure we're at beginning of 2-byte char (need to optimize this!!)
|
|
movem.w d1-d2,-(sp) ; save important regs
|
|
subq #2,sp ; allocate space for CharByte return
|
|
move.l a4,-(sp) ; push text ptr
|
|
move.w d1,-(sp) ; push offset
|
|
_CharByte
|
|
tst.w (sp)+ ; are we at 2nd byte of 2-byte char?
|
|
movem.w (sp)+,d1-d2 ; restore important regs
|
|
ble.s @loopProcess ; skip increment if not
|
|
addq.w #1,d1 ; now we're at beginning of char
|
|
|
|
; test for exit, set up for inner loop
|
|
@loopProcess
|
|
cmp.w d2,d1 ; past last start offset?
|
|
bgt.s @doneSearch ; if so, we're done
|
|
lea 0(a4,d1.w),a0 ; working pointer in baseText
|
|
move.l a2,a1 ; key pointer
|
|
move.w d5,d0 ; key length fixed for dbne
|
|
|
|
; inner loop does comparison with key
|
|
@loopMatch
|
|
cmpm.b (a0)+,(a1)+ ; do baseText bytes match key?
|
|
dbne d0,@loopMatch ; break out if no match or end of key
|
|
|
|
; after inner loop - check for match
|
|
tst.w d0 ; did we go negative?
|
|
bpl.s @loopAdvance ; if not, there was no match
|
|
|
|
; We found a match: save location on stack, increment count, and advance
|
|
; baseText offset after key. Note that key length in d5 has been decremented
|
|
; by one, so after adding it here we still need to do an addq.w #1 to get to
|
|
; the right position.
|
|
move.w d1,-(sp) ; add offset to list
|
|
addq.w #1,d3 ; increment match count
|
|
add.w d6,d4 ; accumulate length difference
|
|
add.w d5,d1 ; skip matched key
|
|
addq.w #1,d1 ; finish skipping matched key
|
|
bra.s @loopProcess ; continue with next baseText position
|
|
|
|
; When we finish the search, we have pushed a word on the stack for each match.
|
|
; A match count is in d3; we need this later for fixing the stack. Also note
|
|
; that we no longer need a2 as a key pointer.
|
|
@doneSearch
|
|
addq.w #1,d5 ; restore real key length
|
|
|
|
; Now we go through and do substitutions in place. The order in which we do
|
|
; this depends on the difference in length between the key and the substitution
|
|
; text: if the substitution text is longer, we do it from the end, otherwise
|
|
; we do it from the beginning.
|
|
|
|
tst.w d3 ; any substitutions?
|
|
beq rtSetResult ; if no, quit.
|
|
tst.w d6 ; check subsText length - key length
|
|
bgt.s rtFromEnd ; if >0, substitute from end.
|
|
|
|
; Substitute from beginning
|
|
; register usage after setup
|
|
; a4 baseText source pointer
|
|
; a3 subsText base pointer
|
|
; a2 temp stack pointer for traversing marker location list
|
|
; a1 baseText dest pointer
|
|
; a0 marker pointer / subsText source pointer
|
|
; d7.l orig baseText length
|
|
; d6 subsText length
|
|
; d5 key length
|
|
; d4 substitution count * (subsText length - key length)
|
|
; d3 substitution count
|
|
; d2.l baseText base pointer
|
|
; d1.l last baseText addr
|
|
; d0 subsText count for dbra
|
|
;
|
|
move.l sp,a2 ; copy stack ptr
|
|
add.w d3,a2 ; only halfway there…
|
|
add.w d3,a2 ; point of beginning of marker list
|
|
move.l a4,d1 ; copy baseText pointer
|
|
add.l d7,d1 ; addr past end of baseText
|
|
add.w d5,d6 ; make subsText length again
|
|
move.l a4,d2 ; save baseText address
|
|
add.w -(a2),a4 ; starting baseText source pointer
|
|
move.l a4,a1 ; starting baseText dest pointer
|
|
bra.s @copySubs
|
|
|
|
@copyBase
|
|
cmp.l a4,d1 ; end of text?
|
|
bls.s @copyDone ; quit if so
|
|
cmp.l a4,a0 ; next marker location?
|
|
beq.s @copySubs ; if so, go copy substitution text
|
|
move.b (a4)+,(a1)+ ; copy the byte
|
|
bra.s @copyBase
|
|
|
|
@copySubs
|
|
move.l a3,a0 ; source pointer
|
|
move.w d6,d0 ; length for dbra
|
|
bra.s @copySubsEnter ; handle case of subsText len=0
|
|
@copySubsLoop
|
|
move.b (a0)+,(a1)+ ; copy the substitution byte
|
|
@copySubsEnter
|
|
dbra d0,@copySubsLoop ; until done
|
|
|
|
add.w d5,a4 ; move baseText source pointer after key
|
|
cmp.l sp,a2 ; are we after last sub?
|
|
bls.s @copyBase ; if so, don't get an invalid marker
|
|
move.l d2,a0 ; copy baseText addr
|
|
add.w -(a2),a0 ; make next marker pointer
|
|
bra.s @copyBase
|
|
|
|
@copyDone
|
|
|
|
; Now reduce handle size if necessary.
|
|
|
|
tst.w d4 ; is it 0?
|
|
beq.s rtSetResult ; if so, no resizing necessary
|
|
|
|
move.l baseText(a6),a0 ; reload baseText handle
|
|
move.w d4,d0 ; length reduction (d4 is < 0)
|
|
ext.l d0
|
|
add.l d7,d0 ; add original length, get new length
|
|
_SetHandleSize
|
|
bmi.s rtFixStack
|
|
bra.s rtSetResult
|
|
|
|
; Substitute from end. First we need to allocate more space.
|
|
rtFromEnd
|
|
move.l baseText(a6),a4 ; reload baseText handle
|
|
move.l a4,a0 ; copy
|
|
move.w d4,d0 ; extra length needed
|
|
ext.l d0
|
|
add.l d7,d0 ; add original length, get new length
|
|
_SetHandleSize
|
|
bmi.s rtFixStack
|
|
move.l (a4),a4 ; baseText ptr
|
|
|
|
move.l subsText(a6),a3 ; reload subsText handle
|
|
move.l (a3),a3 ; subsText ptr
|
|
|
|
; Now do substitution…
|
|
; register usage after setup
|
|
; a4 baseText source pointer
|
|
; a3 subsText end pointer
|
|
; a2 temp stack pointer for traversing marker location list
|
|
; a1 baseText dest pointer
|
|
; a0 marker pointer / subsText source pointer
|
|
; d7.l -(baseText length)
|
|
; d6 subsText length
|
|
; d5 key length
|
|
; d4 substitution count * (subsText length - key length)
|
|
; d3 substitution count
|
|
; d2.l baseText base pointer + key length
|
|
; d1 remaining subs
|
|
; d0 subsText count for dbra
|
|
;
|
|
move.l sp,a2 ; copy stack ptr
|
|
move.l a4,a0 ; copy baseText addr
|
|
add.w d7,a4 ; point after end of baseText (source ptr)
|
|
add.w d5,d6 ; make subsText length again
|
|
move.l a4,a1 ; copy pointer after end of baseText
|
|
add.w d4,a1 ; move past end of expanded space
|
|
add.w d6,a3 ; point after end of subsText
|
|
add.w d5,a0 ; adjust so we point to end of marker
|
|
move.l a0,d2 ; save adjusted base pointer
|
|
add.w (a2)+,a0 ; make first marker pointer
|
|
move.w d3,d1 ; remaining subs
|
|
|
|
@copyBase
|
|
; cmp.l a4,d2 ; end of text?
|
|
; bhi.s @copyDone ; quit if so
|
|
cmp.l a4,a0 ; next marker location?
|
|
beq.s @copySubs ; if so, go copy substitution text
|
|
move.b -(a4),-(a1) ; copy the byte
|
|
bra.s @copyBase
|
|
|
|
@copySubs
|
|
move.l a3,a0 ; source pointer
|
|
move.w d6,d0 ; length for dbra
|
|
bra.s @copySubsEnter ; handle case of subsText len=0
|
|
@copySubsLoop
|
|
move.b -(a0),-(a1) ; copy the substitution byte
|
|
@copySubsEnter
|
|
dbra d0,@copySubsLoop ; until done
|
|
|
|
subq.w #1,d1 ; used up a sub
|
|
ble.s @copyDone ; quit if last sub
|
|
move.l d2,a0 ; copy baseText addr
|
|
add.w (a2)+,a0 ; make next marker pointer
|
|
sub.w d5,a4 ; move baseText source pointer after key
|
|
bra.s @copyBase
|
|
|
|
@copyDone
|
|
|
|
; clean up and return
|
|
rtSetResult
|
|
move.w d3,d0 ; set up result
|
|
rtFixStack
|
|
add.w d3,d3 ; turn count into word offset
|
|
add.w d3,sp ; kill temp storage
|
|
rtBail
|
|
move.w d0,result(a6)
|
|
movem.l (sp)+,a2-a4/d3-d7 ; restore registers
|
|
move.w #rtArgs,d0 ; set up for StdUnlink
|
|
bra StdUnlink
|
|
endwith
|
|
|
|
endproc
|
|
end |