; Substring assigment eg. LET a$(p0 TO p1) = "xxxx"
; HL = Start of string
; TOP of the stack -> p1 (16 bit, unsigned)
; TOP -1 of the stack -> p0 register
; TOP -2 Flag (popped out in A register)
; 		A Register	=> 0 if HL is not freed from memory
;					=> Not 0 if HL must be freed from memory on exit
; TOP -3 B$ address

#include once <mem/free.asm>

    push namespace core

__LETSUBSTR:
    PROC

    LOCAL __CONT0
    LOCAL __CONT1
    LOCAL __CONT2
    LOCAL __FREE_STR

    exx
    pop hl ; Return address
    pop de ; p1
    pop bc ; p0
    exx

    pop af ; Flag
    ex af, af'	; Save it for later

    pop de ; B$

    exx
    push hl ; push ret addr back
    exx
    push de ; B$ addr to be freed upon return (if A != 0)

    ld a, h
    or l
    jp z, __FREE_STR ; Return if null

    ld c, (hl)
    inc hl
    ld b, (hl) ; BC = Str length
    inc hl	; HL = String start
    push bc

    exx
    ex de, hl
    or a
    sbc hl, bc ; HL = Length of string requested by user
    inc hl	   ; len (a$(p0 TO p1)) = p1 - p0 + 1
    ex de, hl  ; Saves it in DE

    pop hl	   ; HL = String length
    exx
    jp c, __FREE_STR	   ; Return if p0 > p1
    exx

    or a
    sbc hl, bc ; P0 >= String length?
    exx

    jp z, __FREE_STR	   ; Return if equal
    jp c, __FREE_STR	   ; Return if greater

    exx
    add hl, bc ; Add it back

    sbc hl, de ; Length of substring > string => Truncate it
    add hl, de ; add it back
    jr nc, __CONT0 ; Length of substring within a$

    ld d, h
    ld e, l	   ; Truncate length of substring to fit within the strlen

__CONT0:	   ; At this point DE = Length of substring to copy
    ; BC = start of char to copy
    push de

    push bc
    exx
    pop bc

    add hl, bc ; Start address (within a$) so copy from b$ (in DE)

    push hl
    exx
    pop hl	   ; Start address (within a$) so copy from b$ (in DE)

    ld b, d	   ; Length of string
    ld c, e

    ld (hl), ' '
    ld d, h
    ld e, l
    inc de
    dec bc
    ld a, b
    or c
    jr z, __CONT2

    ; At this point HL = DE = Start of Write zone in a$
    ; BC = Number of chars to write

    ldir

__CONT2:

    pop bc	; Recovers Length of string to copy
    exx
    ex de, hl  ; HL = Source, DE = Target

    ld a, h
    or l
    jp z, __FREE_STR ; Return if B$ is NULL

    ld c, (hl)
    inc hl
    ld b, (hl)
    inc hl

    ld a, b
    or c
    jp z, __FREE_STR ; Return if len(b$) = 0

    ; Now if len(b$) < len(char to copy), copy only len(b$) chars

    push de
    push hl
    push bc
    exx
    pop hl	; LEN (b$)
    or a
    sbc hl, bc
    add hl, bc
    jr nc, __CONT1

    ; If len(b$) < len(to copy)
    ld b, h ; BC = len(to copy)
    ld c, l

__CONT1:
    pop hl
    pop de
    ldir	; Copy b$ into a$(x to y)

__FREE_STR:
    pop hl
    ex af, af'
    or a		; If not 0, free
    jp nz, __MEM_FREE
    ret

    ENDP

    pop namespace
