2019-04-30 15:51:39 -04:00
|
|
|
; run RLA the number of times specified in B
|
|
|
|
rlaX:
|
|
|
|
; first, see if B == 0 to see if we need to bail out
|
|
|
|
inc b
|
|
|
|
dec b
|
|
|
|
ret z ; Z flag means we had B = 0
|
|
|
|
.loop: rla
|
|
|
|
djnz .loop
|
|
|
|
ret
|
|
|
|
|
|
|
|
callHL:
|
|
|
|
jp (hl)
|
|
|
|
ret
|
|
|
|
|
2019-05-12 22:07:21 -04:00
|
|
|
; HL - DE -> HL
|
|
|
|
subDEFromHL:
|
|
|
|
push af
|
|
|
|
ld a, l
|
|
|
|
sub e
|
|
|
|
ld l, a
|
|
|
|
ld a, h
|
2019-05-17 20:47:43 -04:00
|
|
|
sbc a, d
|
2019-05-12 22:07:21 -04:00
|
|
|
ld h, a
|
|
|
|
pop af
|
|
|
|
ret
|
|
|
|
|
2019-05-09 21:21:08 -04:00
|
|
|
; Returns length of string at (HL) in A.
|
|
|
|
strlen:
|
|
|
|
push bc
|
|
|
|
push hl
|
|
|
|
ld bc, 0
|
|
|
|
ld a, 0 ; look for null char
|
|
|
|
.loop:
|
|
|
|
cpi
|
|
|
|
jp z, .found
|
|
|
|
jr .loop
|
|
|
|
.found:
|
|
|
|
; How many char do we have? the (NEG BC)-1, which started at 0 and
|
|
|
|
; decreased at each CPI call. In this routine, we stay in the 8-bit
|
|
|
|
; realm, so C only.
|
|
|
|
ld a, c
|
|
|
|
neg
|
|
|
|
dec a
|
|
|
|
pop hl
|
|
|
|
pop bc
|
|
|
|
ret
|
|
|
|
|
2019-05-14 15:42:15 -04:00
|
|
|
; Compares strings pointed to by HL and DE up to A count of characters in a
|
|
|
|
; case-insensitive manner.
|
|
|
|
; If equal, Z is set. If not equal, Z is reset.
|
|
|
|
strncmpI:
|
|
|
|
push bc
|
|
|
|
push hl
|
|
|
|
push de
|
|
|
|
|
|
|
|
ld b, a
|
|
|
|
.loop:
|
|
|
|
ld a, (de)
|
2019-05-17 09:50:11 -04:00
|
|
|
call upcase
|
2019-05-14 15:42:15 -04:00
|
|
|
ld c, a
|
|
|
|
ld a, (hl)
|
2019-05-17 09:50:11 -04:00
|
|
|
call upcase
|
2019-05-14 15:42:15 -04:00
|
|
|
cp c
|
|
|
|
jr nz, .end ; not equal? break early. NZ is carried out
|
|
|
|
; to the called
|
|
|
|
or a ; cp 0. If our chars are null, stop the cmp
|
|
|
|
jr z, .end ; The positive result will be carried to the
|
|
|
|
; caller
|
|
|
|
inc hl
|
|
|
|
inc de
|
|
|
|
djnz .loop
|
|
|
|
; Success
|
|
|
|
; We went through all chars with success. Ensure Z
|
|
|
|
cp a
|
|
|
|
.end:
|
|
|
|
pop de
|
|
|
|
pop hl
|
|
|
|
pop bc
|
|
|
|
; Because we don't call anything else than CP that modify the Z flag,
|
|
|
|
; our Z value will be that of the last cp (reset if we broke the loop
|
|
|
|
; early, set otherwise)
|
|
|
|
ret
|
|
|
|
|
2019-05-17 13:14:16 -04:00
|
|
|
; Compares strings pointed to by HL and DE until one of them hits its null char.
|
|
|
|
; If equal, Z is set. If not equal, Z is reset.
|
|
|
|
strcmp:
|
|
|
|
push hl
|
|
|
|
push de
|
|
|
|
|
|
|
|
.loop:
|
|
|
|
ld a, (de)
|
|
|
|
cp (hl)
|
|
|
|
jr nz, .end ; not equal? break early. NZ is carried out
|
|
|
|
; to the called
|
|
|
|
cp 0 ; If our chars are null, stop the cmp
|
|
|
|
jr z, .end ; The positive result will be carried to the
|
|
|
|
; caller
|
|
|
|
inc hl
|
|
|
|
inc de
|
|
|
|
jr .loop
|
|
|
|
|
|
|
|
.end:
|
|
|
|
pop de
|
|
|
|
pop hl
|
|
|
|
; Because we don't call anything else than CP that modify the Z flag,
|
|
|
|
; our Z value will be that of the last cp (reset if we broke the loop
|
|
|
|
; early, set otherwise)
|
|
|
|
ret
|
|
|
|
|
2019-05-19 09:06:24 -04:00
|
|
|
; Copy string from (HL) in (DE), that is, copy bytes until a null char is
|
|
|
|
; encountered. The null char is also copied.
|
|
|
|
; HL and DE point to the char right after the null char.
|
|
|
|
strcpyM:
|
|
|
|
ld a, (hl)
|
|
|
|
ld (de), a
|
|
|
|
inc hl
|
|
|
|
inc de
|
|
|
|
or a
|
|
|
|
jr nz, strcpyM
|
|
|
|
ret
|
|
|
|
|
|
|
|
; Like strcpyM, but preserve HL and DE
|
|
|
|
strcpy:
|
|
|
|
push hl
|
|
|
|
push de
|
|
|
|
call strcpyM
|
|
|
|
pop de
|
|
|
|
pop hl
|
|
|
|
ret
|
|
|
|
|
2019-04-30 15:51:39 -04:00
|
|
|
; If string at (HL) starts with ( and ends with ), "enter" into the parens
|
|
|
|
; (advance HL and put a null char at the end of the string) and set Z.
|
|
|
|
; Otherwise, do nothing and reset Z.
|
|
|
|
enterParens:
|
|
|
|
ld a, (hl)
|
|
|
|
cp '('
|
|
|
|
ret nz ; nothing to do
|
|
|
|
push hl
|
|
|
|
ld a, 0 ; look for null char
|
|
|
|
; advance until we get null
|
|
|
|
.loop:
|
|
|
|
cpi
|
|
|
|
jp z, .found
|
|
|
|
jr .loop
|
|
|
|
.found:
|
|
|
|
dec hl ; cpi over-advances. go back to null-char
|
|
|
|
dec hl ; looking at the last char before null
|
|
|
|
ld a, (hl)
|
|
|
|
cp ')'
|
|
|
|
jr nz, .doNotEnter
|
|
|
|
; We have parens. While we're here, let's put a null
|
|
|
|
xor a
|
|
|
|
ld (hl), a
|
|
|
|
pop hl ; back at the beginning. Let's advance.
|
|
|
|
inc hl
|
|
|
|
cp a ; ensure Z
|
|
|
|
ret ; we're good!
|
|
|
|
.doNotEnter:
|
|
|
|
pop hl
|
2019-05-17 09:50:11 -04:00
|
|
|
call unsetZ
|
2019-04-30 15:51:39 -04:00
|
|
|
ret
|
|
|
|
|
2019-05-17 16:17:22 -04:00
|
|
|
; Scans (HL) and sets Z according to whether the string is double quoted, that
|
|
|
|
; is, starts with a " and ends with a ". If it is double quoted, "enter" them,
|
|
|
|
; that is, advance HL by one and transform the ending quote into a null char.
|
|
|
|
; If the string isn't double-enquoted, HL isn't changed.
|
|
|
|
enterDoubleQuotes:
|
|
|
|
ld a, (hl)
|
|
|
|
cp '"'
|
|
|
|
ret nz
|
|
|
|
push hl
|
|
|
|
inc hl
|
|
|
|
ld a, (hl)
|
|
|
|
or a ; already end of string?
|
|
|
|
jr z, .nomatch
|
|
|
|
xor a
|
|
|
|
call findchar ; go to end of string
|
|
|
|
dec hl
|
|
|
|
ld a, (hl)
|
|
|
|
cp '"'
|
|
|
|
jr nz, .nomatch
|
|
|
|
; We have a match, replace ending quote with null char
|
|
|
|
xor a
|
|
|
|
ld (hl), a
|
|
|
|
; Good, let's go back
|
|
|
|
pop hl
|
|
|
|
; ... but one char further
|
|
|
|
inc hl
|
|
|
|
cp a ; ensure Z
|
|
|
|
ret
|
|
|
|
.nomatch:
|
|
|
|
call unsetZ
|
|
|
|
pop hl
|
|
|
|
ret
|
|
|
|
|
2019-05-14 15:42:15 -04:00
|
|
|
; Find string (HL) in string list (DE) of size B, in a case-insensitive manner.
|
|
|
|
; Each string is C bytes wide.
|
2019-04-30 21:13:37 -04:00
|
|
|
; Returns the index of the found string. Sets Z if found, unsets Z if not found.
|
|
|
|
findStringInList:
|
|
|
|
push de
|
|
|
|
push bc
|
|
|
|
.loop:
|
|
|
|
ld a, c
|
2019-05-14 15:42:15 -04:00
|
|
|
call strncmpI
|
2019-04-30 21:13:37 -04:00
|
|
|
ld a, c
|
2019-05-17 09:50:11 -04:00
|
|
|
call addDE
|
2019-04-30 21:13:37 -04:00
|
|
|
jr z, .match
|
|
|
|
djnz .loop
|
|
|
|
; no match, Z is unset
|
|
|
|
pop bc
|
|
|
|
pop de
|
|
|
|
ret
|
|
|
|
.match:
|
|
|
|
; Now, we want the index of our string, which is equal to our initial B
|
|
|
|
; minus our current B. To get this, we have to play with our registers
|
|
|
|
; and stack a bit.
|
|
|
|
ld d, b
|
|
|
|
pop bc
|
|
|
|
ld a, b
|
|
|
|
sub d
|
|
|
|
pop de
|
|
|
|
cp a ; ensure Z
|
|
|
|
ret
|
2019-05-17 22:22:10 -04:00
|
|
|
|
|
|
|
|
|
|
|
; DE * BC -> DE (high) and HL (low)
|
|
|
|
multDEBC:
|
|
|
|
ld hl, 0
|
|
|
|
ld a, 0x10
|
|
|
|
.loop:
|
|
|
|
add hl, hl
|
|
|
|
rl e
|
|
|
|
rl d
|
|
|
|
jr nc, .noinc
|
|
|
|
add hl, bc
|
|
|
|
jr nc, .noinc
|
2019-05-18 15:41:21 -04:00
|
|
|
inc de
|
2019-05-17 22:22:10 -04:00
|
|
|
.noinc:
|
|
|
|
dec a
|
2019-05-18 15:41:21 -04:00
|
|
|
jr nz, .loop
|
2019-05-17 22:22:10 -04:00
|
|
|
ret
|