mirror of
https://github.com/nathanriggs/AppleIIAsm-Collection.git
synced 2024-12-11 09:49:17 +00:00
16c1731e54
- bugfixes - implemented required library - commenting updates - .min of every routine
845 lines
21 KiB
Plaintext
845 lines
21 KiB
Plaintext
*
|
|
JMP SUBSTRINGSX
|
|
*
|
|
*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*
|
|
* *
|
|
* SUBSTRING ROUTINE LIBRARY *
|
|
* *
|
|
* AUTHOR: NATHAN RIGGS *
|
|
* CONTACT: NATHAN.RIGGS@ *
|
|
* OUTLOOK.COM *
|
|
* *
|
|
* VERSION: 0.2.0 *
|
|
* DATE: 30-OCT-2018 *
|
|
* ASSEMBLER: MERLIN 8 PRO *
|
|
* OS: DOS 3.3 *
|
|
* LICENSE: APACHE 2.0 *
|
|
* *
|
|
* THIS IS A LIBRARY FOR USING *
|
|
* SUBSTRING OPERATIONS. *
|
|
* *
|
|
*------------------------------*
|
|
* *
|
|
* LIST OF ROUTINES *
|
|
* *
|
|
* SUBPOS : FIND POS OF SUBSTR *
|
|
* SUBCOPY : COPY SUBSTRING *
|
|
* SUBDEL : DELETE SUBSTRING *
|
|
* SUBINS : INSERT SUBSTRING *
|
|
* *
|
|
*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*
|
|
*
|
|
*``````````````````````````````*
|
|
* SUBPOS :: SUBSTRING POSITION *
|
|
*- -*
|
|
* FIND THE POSITION OF A SUB- *
|
|
* STRING WITHIN ANOTHER STRING *
|
|
*- -*
|
|
* CLOBBERS: *
|
|
* *
|
|
* FLAGS: ????---- REG: AXYM *
|
|
*- -*
|
|
* CYCLES: ??? *
|
|
* SIZE: *
|
|
*- -*
|
|
* USAGE: *
|
|
* *
|
|
* LDA #>STR ; STRING ADDR *
|
|
* PHA *
|
|
* LDA #<STR *
|
|
* PHA *
|
|
* LDA #>SUB ; SUBSTR ADDR *
|
|
* PHA *
|
|
* LDA #<SUB *
|
|
* JSR SUBPOS *
|
|
*- -*
|
|
* ENTRY *
|
|
* *
|
|
* TOP OF STACK *
|
|
* *
|
|
* LOW BYTE OF RETURN ADDRESS *
|
|
* LOW BYTE OF SUBSTRING ADDR *
|
|
* HI BYTE OF SUBSTRING ADDR *
|
|
* LO BYTE OF STRING ADDR *
|
|
* HI BYTE OF STRING ADDRESS *
|
|
* HI BYTE OF RETURN ADDRESS *
|
|
*- -*
|
|
* EXIT *
|
|
* *
|
|
* TOP OF STACK *
|
|
* *
|
|
* LOW BYTE OF RETURN ADDRESS *
|
|
* HI BYTE OF RETURN ADDRESS *
|
|
* *
|
|
* .Y = CLOBBERED; TRASH *
|
|
* .X = CLOBBERED; TRASH *
|
|
* .A = INDEX OF SUBSTRING IF *
|
|
* FOUND; OTHERWISE, 0 *
|
|
* *
|
|
* [RETURN] = INDEX OF SUBSTR; *
|
|
* 0 IF NOT FOUND *
|
|
* [RETLEN] = 1 (INDEX LENGTH) *
|
|
*- -*
|
|
* ADAPTED FROM LEVANTHAL AND *
|
|
* WINTHROP'S /6502 ASSEMBLY *
|
|
* LANGUAGE ROUTINES/. MAY NOT *
|
|
* FALL UNDER APACHE 2.0 UNTIL *
|
|
* HEAVILY MODIFIED. *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
SUBPOS
|
|
*
|
|
** SAVE RETURN ADDRESS
|
|
*
|
|
PLA
|
|
STA RETADR
|
|
PLA
|
|
STA RETADR+1
|
|
*
|
|
** GET PARAMETERS
|
|
*
|
|
PLA
|
|
STA ADDR2
|
|
PLA
|
|
STA ADDR2+1
|
|
PLA
|
|
STA ADDR1
|
|
PLA
|
|
STA ADDR1+1
|
|
*
|
|
** RESTORE RETURN ADDRESS
|
|
*
|
|
LDA RETADR+1
|
|
PHA
|
|
LDA RETADR
|
|
PHA
|
|
*
|
|
:POS
|
|
LDY #0
|
|
LDA (ADDR1),Y ; GET LENGTH OF STRING
|
|
BEQ :NOTFND ; EXIT IF LENGTH = 0
|
|
STA :SLEN
|
|
LDA (ADDR2),Y ; GET SUBSTR LENGTH
|
|
BEQ :NOTFND ; EXIT IF SUB LENGTH = 0
|
|
STA :SUBLEN
|
|
*
|
|
** IF THE SUBSTR IS LONGER THAN STR, DECLARE THE
|
|
** SUBSTR NOT FOUND
|
|
*
|
|
LDA :SUBLEN
|
|
CMP :SLEN
|
|
BEQ :LENOK
|
|
BCS :NOTFND ; CANNOT FIND SUBSTR IF
|
|
; LONGER THAN STR
|
|
*
|
|
** START, SEARCH, CONTINUE UNTIL
|
|
** REMAINING STR SHORTER THAN SUBSTR
|
|
*
|
|
:LENOK
|
|
LDA #1
|
|
STA :SINDEX ; START LOOKING AT FIRST
|
|
; CHARACTER OF STRING
|
|
LDA :SLEN ; CONT UNTIL REMAINING STR
|
|
; TOO SHORT
|
|
SEC ; COUNT=STR LEN - SUB LEN+1
|
|
SBC :SUBLEN
|
|
STA :SCOUNT
|
|
INC :SCOUNT
|
|
*
|
|
** SEARCH FOR SUBSTRING IN STRING
|
|
*
|
|
:SLP1
|
|
LDA :SINDEX
|
|
STA :SIDX ; START STR AT INDEX
|
|
LDA #1
|
|
STA :SUBIDX ; START SUB IND AT 1
|
|
*
|
|
** LOOK FOR SUBSTRING BEGINNING AT INDEX
|
|
*
|
|
:CMPLP
|
|
LDY :SIDX
|
|
LDA (ADDR1),Y ; GET NEXT CHAR FROM STR
|
|
LDY :SUBIDX
|
|
CMP (ADDR2),Y ; COMPARE TO NEXT SUB CHAR
|
|
BNE :SLP2 ; BR IF SUB NOT HERE
|
|
LDY :SUBIDX
|
|
CPY :SUBLEN ; TEST IF WE ARE DONE
|
|
BEQ :FOUND ; BR IF ALL CHARS WERE EQUAL
|
|
INY ; ELSE INC TO NEXT CHAR
|
|
STY :SUBIDX
|
|
INC :SIDX
|
|
JMP :CMPLP ; CONTINUE
|
|
*
|
|
** ARRIVE HERE IF SUBSTRING NOT FOUND
|
|
*
|
|
:SLP2
|
|
INC :SINDEX ; INCREMENT INDEX
|
|
DEC :SCOUNT ; DEC COUNT
|
|
BNE :SLP1 ; BR IF NOT DONE
|
|
BEQ :NOTFND ; ELSE EXIT TO NOT FOUND
|
|
*
|
|
:FOUND
|
|
LDA :SINDEX ; FOUND, A = STARTING IDX
|
|
JMP :EXIT
|
|
*
|
|
:NOTFND
|
|
LDA #0 ; SUB NOT FOUND, A=0
|
|
:EXIT
|
|
STA RETURN
|
|
LDY #1
|
|
STY RETLEN
|
|
RTS
|
|
*
|
|
** DATA
|
|
*
|
|
:SLEN DS 1
|
|
:SUBLEN DS 1
|
|
:SINDEX DS 1
|
|
:SUBIDX DS 1
|
|
:SCOUNT DS 1
|
|
:SIDX DS 1
|
|
*
|
|
*``````````````````````````````*
|
|
* SUBCOPY :: COPY SUBSTRING *
|
|
*- -*
|
|
* COPY A SUBSTRING FROM A *
|
|
* STRING TO [RETURN]. *
|
|
*- -*
|
|
* CLOBBERS: *
|
|
* *
|
|
* FLAGS: ????---- REG: AXYM *
|
|
*- -*
|
|
* CYCLES: ??? *
|
|
* SIZE: *
|
|
*- -*
|
|
* USAGE: *
|
|
* *
|
|
* LDA #>STR ; SOURCE STRING *
|
|
* PHA *
|
|
* LDA #<STR *
|
|
* PHA *
|
|
* LDA #IND ; COPY START INDEX *
|
|
* PHA *
|
|
* LDA LEN ; LENGTH OF SUBSTR *
|
|
* PHA *
|
|
* LDA MLEN ; MAX LENGTH *
|
|
* PHA *
|
|
* JSR SUBCOPY *
|
|
*- -*
|
|
* ENTRY *
|
|
* *
|
|
* TOP OF STACK *
|
|
* *
|
|
* LOW BYTE OF RETURN ADDRESS *
|
|
* HI BYTE OF RETURN ADDRESS *
|
|
* MAX LENGTH OF DEST STRING *
|
|
* NUMBER OF BYTES TO COPY *
|
|
* STARTING INDEX TO COPY FROM *
|
|
* LO BYTE OF SRC STRING ADDR *
|
|
* HI BYTE OF SOURCE STR ADDR *
|
|
*- -*
|
|
* EXIT *
|
|
* *
|
|
* TOP OF STACK *
|
|
* *
|
|
* LOW BYTE OF RETURN ADDRESS *
|
|
* HI BYTE OF RETURN ADDRESS *
|
|
* *
|
|
* .Y = TRASH *
|
|
* .X = TRASH *
|
|
* .A = TRASH *
|
|
* *
|
|
* CARRY FLAG WILL BE 0 IF NO *
|
|
* ERRORS; ELSE, CARRY = 1 *
|
|
*- -*
|
|
* ADAPTED FROM LEVANTHAL AND *
|
|
* WINTHROP'S /6502 ASSEMBLY *
|
|
* LANGUAGE ROUTINES/. *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
SUBCOPY
|
|
*
|
|
** SAVE RETURN ADDRESS
|
|
*
|
|
PLA
|
|
STA RETADR
|
|
PLA
|
|
STA RETADR+1
|
|
*
|
|
** GET PARAMETERS
|
|
*
|
|
PLA
|
|
STA :MLEN
|
|
PLA
|
|
STA :SCNT
|
|
STA RETLEN
|
|
PLA
|
|
STA :SINDEX
|
|
PLA
|
|
STA ADDR1
|
|
PLA
|
|
STA ADDR1+1
|
|
*
|
|
LDA #<RETURN
|
|
STA ADDR2
|
|
LDA #>RETURN
|
|
STA ADDR2+1
|
|
*
|
|
** RESTORE RETURN ADDRESS
|
|
*
|
|
LDA RETADR+1
|
|
PHA
|
|
LDA RETADR
|
|
PHA
|
|
*
|
|
LDA #0
|
|
STA :S2LEN ; DESTINATION LENGTH = 0
|
|
STA :SCERR ; ASSUME NO ERRORS
|
|
*
|
|
** CHECK FOR ZERO BYTES TO COPY OR ZERO MAX SUBSTR LENGTH
|
|
*
|
|
LDA :SCNT
|
|
BEQ :OKEXIT ; BR IF 0 BYTES TO COPY,
|
|
; S2A WILL JUST HAVE ZERO LENGTH
|
|
LDA :MLEN
|
|
BEQ :EREXIT ; ERROR EXIT IF SUBSTR HAS
|
|
; ZERO MAX LENGTH
|
|
LDA :SINDEX
|
|
BEQ :EREXIT ; ERROR EXIT IF START IDX = 0
|
|
*
|
|
** CHECK IF SRC STR REACHES STARTING INDEX
|
|
*
|
|
LDY #0
|
|
LDA (ADDR1),Y ;
|
|
STA :S1LEN ; GET LENGTH OF SOURCE STRING
|
|
CMP :SINDEX ; COMPARE TO STARTING INDEX
|
|
BCC :EREXIT ; ERROR EXIT IF INDEX TOO BIG
|
|
*
|
|
** CHECK THAT WE DO NOT COPY BEYOND THE END OF
|
|
** THE SOURCE STRING.
|
|
** IF INDEX + COUNT -1 > SLEN THEN
|
|
** COUNT = SLEN - SINDEX + 1
|
|
*
|
|
LDA :SINDEX
|
|
CLC
|
|
ADC :SCNT
|
|
BCS :RECALC
|
|
TAX ; BR IF INDEX + COUNT > 255
|
|
DEX
|
|
CPX :S1LEN
|
|
BCC :CNT10K ; BR IF IND + CNT - 1 < S1LEN
|
|
BEQ :CNT10K ; OR EQUAL
|
|
*
|
|
** THE CALLER ASKED FOR TOO MANY CHARS SO
|
|
** JUST RETURN EVERYTHING BETWEEN INDEX AND
|
|
** END OF STRING. SO CNT = S1LEN - INDEX + 1
|
|
*
|
|
:RECALC
|
|
LDA :S1LEN ; RECALCULATE COUNT
|
|
SEC
|
|
SBC :SINDEX
|
|
STA :SCNT
|
|
INC :SCNT ; CNT = S1LEN - IND + 1
|
|
LDA #$0FF
|
|
STA :SCERR ; INDICATE TRUNCATION
|
|
*
|
|
** CHECK IF COUNT IS <= THE MAXIMUM LENGTH
|
|
** OF THE DEST STRING. IF NOT, THEN SET COUNT TO
|
|
** MAX LENGTH.
|
|
** IF COUNT > MAXLEN THEN
|
|
** COUNT = MAXLEN
|
|
*
|
|
:CNT10K
|
|
LDA :SCNT
|
|
CMP :MLEN ; IF CNT > M SUBSTR LEN ?
|
|
BCC :CNT20K ; BR IF CNT < MAXLEN
|
|
BEQ :CNT20K ; BR IF CNT = MAXLEN
|
|
LDA :MLEN
|
|
STA :SCNT ; ELSE CNT = MAXLEN
|
|
LDA #$0FF
|
|
STA :SCERR ; INDICATE DEST STR OVERFLOW
|
|
*
|
|
** EVERYTHING IS SET UP SO MOVE THE
|
|
** SUBSTRING TO THE DESTINATION STRING
|
|
*
|
|
:CNT20K
|
|
LDX :SCNT ; REG X WILL BE COUNTER
|
|
BEQ :EREXIT ; ERR IF 0
|
|
LDA #1 ; START WITH 1ST CHAR IN DEST
|
|
STA :S2LEN ; RUNNING DEST INDEX
|
|
; __SINDEX IS SRC INDEX
|
|
:MVLP
|
|
LDY :SINDEX
|
|
LDA (ADDR1),Y ; GET NEXT SRC CHAR
|
|
LDY :S2LEN
|
|
STA (ADDR2),Y ; MOVE NEXT CHAR TO DEST
|
|
INC :SINDEX ; INC SRC INDEX
|
|
INC :S2LEN ; INC DEST INDEX
|
|
DEX ; DECREMENT COUNTER
|
|
BNE :MVLP ; CONT UNTIL CNT = 0
|
|
DEC :S2LEN ; SUBSTR LEN=FINAL DEST IND-1
|
|
LDA :SCERR ; CHECK FOR ANY ERRORS
|
|
BNE :EREXIT ; BR IF STR TRUNCATED OR OVERFLOW
|
|
*
|
|
** GOOD EXIT
|
|
*
|
|
:OKEXIT
|
|
CLC
|
|
BCC :EXIT
|
|
*
|
|
** ERROR EXIT
|
|
*
|
|
:EREXIT
|
|
SEC
|
|
*
|
|
** STORE LENGTH BYTE IN FRONT OF SUBSTR
|
|
*
|
|
:EXIT
|
|
LDA :S2LEN
|
|
LDY #0
|
|
STA (ADDR2),Y
|
|
STA RETLEN
|
|
RTS
|
|
*
|
|
** DATA
|
|
*
|
|
:S1LEN DS 1
|
|
:S2LEN DS 1
|
|
:MLEN DS 1
|
|
:SCNT DS 1
|
|
:SINDEX DS 1
|
|
:SCERR DS 1
|
|
*
|
|
*``````````````````````````````*
|
|
* SUBDEL :: DELETE SUBSTRING *
|
|
*- -*
|
|
* DELETE A SUBSTRING FROM A *
|
|
* STRING. *
|
|
*- -*
|
|
* CLOBBERS: *
|
|
* *
|
|
* FLAGS: ????---- REG: AXYM *
|
|
*- -*
|
|
* CYCLES: ??? *
|
|
* SIZE: *
|
|
*- -*
|
|
* USAGE: *
|
|
* *
|
|
* LDA #>STR ; STRING ADDRESS *
|
|
* PHA *
|
|
* LDA #<STR *
|
|
* PHA *
|
|
* LDA IND ; DEL START INDEX *
|
|
* PHA *
|
|
* LDA LEN ; LENGTH OF DELETE *
|
|
* PHA *
|
|
* JSR SUBDEL *
|
|
*- -*
|
|
* ENTRY *
|
|
* *
|
|
* TOP OF STACK *
|
|
* *
|
|
* LOW BYTE OF RETURN ADDRESS *
|
|
* HI BYTE OF RETURN ADDRESS *
|
|
* NUMBER OF BYTES TO DELETE *
|
|
* STARTING INDEX OF DELETION *
|
|
* LO BYTE OF STRING ADDRESS *
|
|
* HI BYTE OF STRING ADDRESS *
|
|
*- -*
|
|
* EXIT *
|
|
* *
|
|
* TOP OF STACK *
|
|
* *
|
|
* LOW BYTE OF RETURN ADDRESS *
|
|
* HI BYTE OF RETURN ADDRESS *
|
|
* *
|
|
* .Y = TRASH *
|
|
* .X = TRASH *
|
|
* .A = TRASH *
|
|
* *
|
|
* IF NO ERRORS, CARRY = 0; *
|
|
* ELSE, CARRY = 1 *
|
|
*- -*
|
|
* ADAPTED FROM LEVANTHAL AND *
|
|
* WINTHROP'S /6502 ASSEMBLY *
|
|
* LANGUAGE ROUTINES/. *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
SUBDEL
|
|
*
|
|
** SAVE RETURN ADDRES
|
|
*
|
|
PLA
|
|
TAY
|
|
PLA
|
|
TAX
|
|
*
|
|
** GET PARAMTERS
|
|
*
|
|
PLA
|
|
STA :SCNT
|
|
PLA
|
|
STA :SINDEX
|
|
PLA
|
|
STA ADDR1
|
|
PLA
|
|
STA ADDR1+1
|
|
*
|
|
** RESTORE RETURN ADDRESS
|
|
*
|
|
TXA
|
|
PHA
|
|
TYA
|
|
PHA
|
|
*
|
|
** INITIALIZE ERROR INDICATOR TO 0
|
|
*
|
|
LDY #0
|
|
STY :SCERR
|
|
LDA (ADDR1),Y
|
|
STA :S1LEN ; GET STRING LENGTH
|
|
*
|
|
** CHECK FOR A NON-ZERO COUNT AND INDEX
|
|
*
|
|
LDA :SCNT
|
|
BEQ :OKEXIT
|
|
; GOOD EXIT IF NO DELETE
|
|
LDA :SINDEX
|
|
BEQ :ERREXIT ; ERR EXIT IF START = 0
|
|
*
|
|
** CHECK FOR STARTING INDEX WITHIN THE STRING
|
|
*
|
|
* EXIT IF IT IS NOT
|
|
*
|
|
LDA :S1LEN
|
|
CMP :SINDEX
|
|
BCC :ERREXIT
|
|
*
|
|
** BE SURE THE NUMBER OF CHARACTERS REQUESTED
|
|
** TO BE DELETED ARE PRESENT.
|
|
** IF NOT, THEN ONLY DELETE FROM THE INDEX
|
|
** TO THE END OF THE STRING.
|
|
*
|
|
LDA :SINDEX
|
|
CLC
|
|
ADC :SCNT
|
|
BCS :TRUNC ;TRUNCATE IF INDEX
|
|
; + COUNT > 255
|
|
STA :SIDX ; SAVE INDEX + COUNT AS
|
|
; THE SOURCE INDEX
|
|
TAX ; X = INDEX + COUNT
|
|
DEX
|
|
CPX :S1LEN
|
|
BCC :CNTOK ; BR IF IND + CNT - 1
|
|
; < __S1LEN
|
|
; ELSE JUST TRUNC STRING
|
|
BEQ :TRUNC ; TRUNC BUT NO ERROR--
|
|
; EXACTLY ENOUGH CHARS
|
|
LDA #$0FF
|
|
STA :SCERR ; INDICATE ERROR - NOT
|
|
; ENOUGH CHARS TO DELETE
|
|
*
|
|
** TRUNCATE THE STRING - NO COMPACTING NECESSARY
|
|
*
|
|
:TRUNC
|
|
LDX :SINDEX ; STRING LENGTH =
|
|
; START INDEX - 1
|
|
DEX
|
|
STX :S1LEN
|
|
LDA :SCERR
|
|
BEQ :OKEXIT
|
|
BNE :ERREXIT
|
|
*
|
|
** DELETE THE SUBSTRING BY COMPACTING
|
|
** MOVE ALL CHARS ABOVE THE DELETED AREA DOWN
|
|
*
|
|
:CNTOK
|
|
*
|
|
** CALCULATE NUMBER OF CHARS TO MOVE
|
|
** (SLEN - SIDX + 1)
|
|
*
|
|
LDA :S1LEN ; GET STR LENGTH
|
|
SEC
|
|
SBC :SIDX ; SUBTRACT START INDEX
|
|
TAX
|
|
INX
|
|
BEQ :OKEXIT ; ADD 1 TO INCLUDE LAST
|
|
; CHAR; BR IF CNT = 0
|
|
:MVLP
|
|
LDY :SIDX
|
|
LDA (ADDR1),Y ; GET NEXT CHAR
|
|
LDY :SINDEX
|
|
STA (ADDR1),Y ;MOVE IT DOWN
|
|
INC :SINDEX
|
|
INC :SIDX ; INC DEST, SRC INDEXES
|
|
DEX
|
|
BNE :MVLP ; CONT UNTIL CNT = 0
|
|
LDX :SINDEX
|
|
DEX ; START LENGTH = FINAL
|
|
; DEST INDEX -1
|
|
STX :S1LEN
|
|
*
|
|
** GOOD EXIT
|
|
*
|
|
:OKEXIT
|
|
CLC
|
|
BCC :EXIT
|
|
:ERREXIT
|
|
SEC
|
|
*
|
|
:EXIT
|
|
LDA :S1LEN
|
|
LDY #0
|
|
STA (ADDR1),Y ; SET LENGTH OF STRING
|
|
RTS
|
|
*
|
|
** DATA
|
|
*
|
|
:S1LEN DS 1
|
|
:SCNT DS 1
|
|
:SINDEX DS 1
|
|
:SIDX DS 1
|
|
:SCERR DS 1
|
|
*
|
|
*``````````````````````````````*
|
|
* SUBINS :: INSERT SUBSTRING *
|
|
*- -*
|
|
* INSERT A SUBSTRING INTO *
|
|
* ANOTHER STRING. *
|
|
*- -*
|
|
* CLOBBERS: *
|
|
* *
|
|
* FLAGS: ????---- REG: AXYM *
|
|
*- -*
|
|
* CYCLES: ??? *
|
|
* SIZE: *
|
|
*- -*
|
|
* USAGE: *
|
|
* *
|
|
* LDA #STR ; STRING TO INS TO *
|
|
* PHA *
|
|
* LDA #<STR *
|
|
* PHA *
|
|
* LDA IND ; INDEX TO START INS *
|
|
* PHA *
|
|
* LDA MLEN ; MAX LENGTH OF STR *
|
|
* PHA *
|
|
* LDA #>SUB ; SUBSTRING TO INS *
|
|
* PHA *
|
|
* LDA #<SUB *
|
|
* PHA *
|
|
* JST SUBINS *
|
|
*- -*
|
|
* ENTRY *
|
|
* *
|
|
* TOP OF STACK *
|
|
* *
|
|
* LOW BYTE OF RETURN ADDRESS *
|
|
* HI BYTE OF RETURN ADDRESS *
|
|
* LO BYTE OF SUBSTRING ADDRESS *
|
|
* HI BYTE OF SUBSTRING ADDRESS *
|
|
* MAX LENGTH OF FINAL STRING *
|
|
* STARTING INDEX FOR INSERTION *
|
|
* LO BYTE OF SRC STRING ADDR *
|
|
* HI BYTE OF SOURCE STR ADDR *
|
|
*- -*
|
|
* EXIT *
|
|
* *
|
|
* TOP OF STACK *
|
|
* *
|
|
* LOW BYTE OF RETURN ADDRESS *
|
|
* HI BYTE OF RETURN ADDRESS *
|
|
* *
|
|
* .Y = TRASH *
|
|
* .X = TRASH *
|
|
* .A = TRASH *
|
|
* *
|
|
* CARRY = 0 IF NO ERRORS; ELSE *
|
|
* CARRY = 1 *
|
|
*- -*
|
|
* ADAPTED FROM LEVANTHAL AND *
|
|
* WINTHROP'S /6502 ASSEMBLY *
|
|
* LANGUAGE ROUTINES/. *
|
|
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
|
|
*
|
|
SUBINS
|
|
*
|
|
** GET RETURN ADDRESS
|
|
*
|
|
PLA
|
|
TAY
|
|
PLA
|
|
TAX
|
|
*
|
|
** GET PARAMETERS
|
|
*
|
|
PLA
|
|
STA ADDR2
|
|
PLA
|
|
STA ADDR2+1
|
|
PLA
|
|
STA :MLEN
|
|
PLA
|
|
STA :SINDEX
|
|
PLA
|
|
STA ADDR1
|
|
PLA
|
|
STA ADDR1+1
|
|
*
|
|
** RESTORE RETURN ADDRESS
|
|
*
|
|
TXA
|
|
PHA
|
|
TYA
|
|
PHA
|
|
*
|
|
*
|
|
** ASSUME NO ERRORS
|
|
*
|
|
LDA #0
|
|
STA :SCERR ; ASSUME NO ERR WILL BE FOUND
|
|
*
|
|
** GET SUBSTRING AND STRING LENGTHS
|
|
** IF SUB LENGTH = 0 THEN EXIT NO ERROR
|
|
*
|
|
LDY #0
|
|
LDA (ADDR1),Y
|
|
STA :S1LEN ; GET LENGTH OF STRING
|
|
LDA (ADDR2),Y
|
|
STA :S2LEN ; GET LENGTH OF SUB
|
|
BNE :IDX0
|
|
JMP :OKEXIT ; EXIT OF NO INSERT/ERR
|
|
*
|
|
** IF STARTING INDEX IS 0 THEN ERROR EXIT
|
|
*
|
|
:IDX0
|
|
LDA :SINDEX
|
|
BNE :CHKLEN ; BR OF INDEX NOT 0
|
|
JMP :EREXIT ; ELSE ERROR EXIT
|
|
*
|
|
** CHECK THAT THE RESULTING STRING AFTER THE
|
|
** INSERTION FITS IN THE SOURCE STRING. IF NOT
|
|
** THEN TRUNCATE THE SUBSTRING AND SET
|
|
** THE TRUNCATION FLAG.
|
|
*
|
|
:CHKLEN
|
|
LDA :S2LEN ; GET SUBSTR LENGTH
|
|
CLC
|
|
ADC :S1LEN
|
|
BCS :TRUNC ;TRUN IF S1+S2 LENGTH > 255
|
|
CMP :MLEN ;
|
|
BCC :IDXLEN ; BR IF S1+S2 LEN < MAX LENGTH
|
|
BEQ :IDXLEN ; BR IF EQUAL
|
|
*
|
|
** SUBSTRING DOES NOT FIT, SO TRUNCATE IT
|
|
*
|
|
:TRUNC
|
|
LDA :MLEN ; SUBSTR LEN = MLEN - STR LEN
|
|
SEC
|
|
SBC :S1LEN
|
|
BCC :EREXIT
|
|
BEQ :EREXIT ; ERR IF MLEN < STR LEN OR 0
|
|
; (ORIGINAL STRING WAS TOO LONG)
|
|
STA :S2LEN
|
|
LDA #$0FF
|
|
STA :SCERR ; INDICATE SUBSTR WAS TRUNCATED
|
|
*
|
|
** CHECK THAT INDEX IS WITHIN STRING. IF NOT, CONCAT
|
|
** SUBSTR ONTO THE END OF THE STRING.
|
|
*
|
|
:IDXLEN
|
|
LDA :S1LEN
|
|
CMP :SINDEX ;
|
|
BCS :LENOK ; BR IF INDEX WITHIN STR
|
|
LDX :S1LEN ; ELSE CONCAT SUB AT END OF STR
|
|
INX
|
|
STX :SINDEX ; START RIGHT AFTER END OF STR
|
|
LDA #$0FF
|
|
STA :SCERR ; INDICATE ERR IN INSERT
|
|
LDA :S1LEN
|
|
CLC
|
|
ADC :S2LEN
|
|
STA :S1LEN ; ADD LENGTHS TOGETHER
|
|
JMP :MVESUB ; PERFORM MOVE, NOTHING ELSE TODO
|
|
*
|
|
** OPEN UP A SPACE IN THE SOURCE STRING FOR THE
|
|
** SUBSTRING BY MOVING THE CHARACTERS FROM THE END
|
|
** OF THE SOURCE STRING DOWN TO INDEX, UP BY
|
|
** THE SIZE OF THE STRING.
|
|
*
|
|
:LENOK
|
|
*
|
|
** CALC NUMBER OF CHARS TO MOVE
|
|
** COUNT = STR LEN - START INDEX + 1
|
|
*
|
|
LDA :S1LEN
|
|
SEC
|
|
SBC :SINDEX
|
|
TAX
|
|
INX ; X= NUM OF CHARS TO MOV
|
|
*
|
|
** SET THE SOURCE INDEX AND CALC DEST INDEX
|
|
*
|
|
LDA :S1LEN
|
|
STA :SIDX ; SRC ENDS AT ORIG STR END
|
|
CLC
|
|
ADC :S2LEN
|
|
STA :SBIDX ; DEST ENDS FURTHER BY SUB LEN
|
|
STA :S1LEN ; SET NEW LENGTH TO THIS ALSO
|
|
*
|
|
:OPNLP
|
|
LDY :SIDX
|
|
LDA (ADDR1),Y
|
|
LDY :SBIDX
|
|
STA (ADDR1),Y ; MOVE IT UP IN MEM
|
|
DEC :SIDX
|
|
DEC :SBIDX ; DE DEST IDX, COUNTER
|
|
DEX
|
|
BNE :OPNLP ; CONT UNTIL COUNTER = 0
|
|
*
|
|
** MOVE THE SUBSTR INTO THE OPEN AREA
|
|
*
|
|
:MVESUB
|
|
LDA #1
|
|
STA :SIDX
|
|
; START AT ONE IN THE SUBSTR
|
|
; START AT INDEX IN THE STRING
|
|
LDX :S2LEN ; X = NUM OF CHARS TO MOVE
|
|
*
|
|
:MVELP
|
|
LDY :SIDX
|
|
LDA (ADDR2),Y ; GET NEXT CHAR
|
|
LDY :SINDEX
|
|
STA (ADDR1),Y
|
|
INC :SIDX ; INC SUBSTR INDEX
|
|
INC :SINDEX ; INC STR INDEX
|
|
DEX ; DEC COUNTER
|
|
BNE :MVELP ; CONT UNTIL COUNTER = 0
|
|
LDA :SCERR ; GET ERROR FLAG
|
|
BNE :EREXIT ; BR IF SUBSTR WAS TRUNCED
|
|
*
|
|
:OKEXIT
|
|
CLC
|
|
BCC :EXIT
|
|
:EREXIT
|
|
SEC ; ERROR EXIT
|
|
:EXIT
|
|
LDA :S1LEN
|
|
LDY #0
|
|
STA (ADDR1),Y
|
|
RTS
|
|
*
|
|
** DATA
|
|
*
|
|
:S1LEN DS 1
|
|
:S2LEN DS 1
|
|
:SUBLEN DS 1
|
|
:MLEN DS 1
|
|
:SINDEX DS 1
|
|
:SIDX DS 1
|
|
:SBIDX DS 1
|
|
:SCERR DS 1
|
|
*
|
|
SUBSTRINGSX
|
|
*
|