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