1dec33e02a
Instead of strings of variable length driving the iteration of the registry, we do so through records that keep track of lengths and counts.
228 lines
4.3 KiB
NASM
228 lines
4.3 KiB
NASM
; 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
|
|
|
|
; HL - DE -> HL
|
|
subDEFromHL:
|
|
push af
|
|
ld a, l
|
|
sub e
|
|
ld l, a
|
|
ld a, h
|
|
sbc a, d
|
|
ld h, a
|
|
pop af
|
|
ret
|
|
|
|
; make Z the opposite of what it is now
|
|
toggleZ:
|
|
jp z, unsetZ
|
|
cp a
|
|
ret
|
|
|
|
; Returns length of string at (HL) in A.
|
|
; Doesn't include null termination.
|
|
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
|
|
|
|
; 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)
|
|
call upcase
|
|
ld c, a
|
|
ld a, (hl)
|
|
call upcase
|
|
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
|
|
|
|
; 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
|
|
|
|
; 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
|
|
call unsetZ
|
|
ret
|
|
|
|
; 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
|
|
|
|
; Find string (HL) in string list (DE) of size B, in a case-insensitive manner.
|
|
; Each string is C bytes wide.
|
|
; 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
|
|
call strncmpI
|
|
ld a, c
|
|
call addDE
|
|
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
|
|
|
|
|
|
; 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
|
|
inc de
|
|
.noinc:
|
|
dec a
|
|
jr nz, .loop
|
|
ret
|