mirror of
https://github.com/hsoft/collapseos.git
synced 2024-09-07 14:08:44 +10:00
The goal is to avoid mixing those routines with "character devices" (acia, vpd, kbd) which aren't block devices and have routines that have different expectations. This is a first step to fixing #64.
212 lines
5.6 KiB
NASM
212 lines
5.6 KiB
NASM
; buf - manage line buffer
|
|
;
|
|
; *** Variables ***
|
|
; Number of lines currently in the buffer
|
|
.equ BUF_LINECNT BUF_RAMSTART
|
|
; List of pointers to strings in scratchpad
|
|
.equ BUF_LINES @+2
|
|
; Points to the end of the scratchpad, that is, one byte after the last written
|
|
; char in it.
|
|
.equ BUF_PADEND @+ED_BUF_MAXLINES*2
|
|
; The in-memory scratchpad
|
|
.equ BUF_PAD @+2
|
|
|
|
.equ BUF_RAMEND @+ED_BUF_PADMAXLEN
|
|
|
|
; *** Code ***
|
|
|
|
; On initialization, we read the whole contents of target blkdev and add lines
|
|
; as we go.
|
|
bufInit:
|
|
ld hl, BUF_PAD ; running pointer to end of pad
|
|
ld de, BUF_PAD ; points to beginning of current line
|
|
ld ix, BUF_LINES ; points to current line index
|
|
ld bc, 0 ; line count
|
|
; init pad end in case we have an empty file.
|
|
ld (BUF_PADEND), hl
|
|
.loop:
|
|
call ioGetB
|
|
jr nz, .loopend
|
|
or a ; null? hum, weird. same as LF
|
|
jr z, .lineend
|
|
cp 0x0a
|
|
jr z, .lineend
|
|
ld (hl), a
|
|
inc hl
|
|
jr .loop
|
|
.lineend:
|
|
; We've just finished reading a line, writing each char in the pad.
|
|
; Null terminate it.
|
|
xor a
|
|
ld (hl), a
|
|
inc hl
|
|
; Now, let's register its pointer in BUF_LINES
|
|
ld (ix), e
|
|
inc ix
|
|
ld (ix), d
|
|
inc ix
|
|
inc bc
|
|
ld (BUF_PADEND), hl
|
|
ld de, (BUF_PADEND)
|
|
jr .loop
|
|
.loopend:
|
|
ld (BUF_LINECNT), bc
|
|
ret
|
|
|
|
; transform line index HL into its corresponding memory address in BUF_LINES
|
|
; array.
|
|
bufLineAddr:
|
|
push de
|
|
ex de, hl
|
|
ld hl, BUF_LINES
|
|
add hl, de
|
|
add hl, de ; twice, because two bytes per line
|
|
pop de
|
|
ret
|
|
|
|
; Read line number specified in HL and make HL point to its contents.
|
|
; Sets Z on success, unset if out of bounds.
|
|
bufGetLine:
|
|
push de ; --> lvl 1
|
|
ld de, (BUF_LINECNT)
|
|
call cpHLDE
|
|
pop de ; <-- lvl 1
|
|
jp nc, unsetZ ; HL > (BUF_LINECNT)
|
|
call bufLineAddr
|
|
; HL now points to an item in BUF_LINES.
|
|
call intoHL
|
|
; Now, HL points to our contents
|
|
cp a ; ensure Z
|
|
ret
|
|
|
|
; Given line indexes in HL and DE where HL < DE < CNT, move all lines between
|
|
; DE and CNT by an offset of DE-HL. Also, adjust BUF_LINECNT by DE-HL.
|
|
; WARNING: no bounds check. The only consumer of this routine already does
|
|
; bounds check.
|
|
bufDelLines:
|
|
; Let's start with setting up BC, which is (CNT-DE) * 2
|
|
push hl ; --> lvl 1
|
|
ld hl, (BUF_LINECNT)
|
|
scf \ ccf
|
|
sbc hl, de
|
|
; mult by 2 and we're done
|
|
sla l \ rl h
|
|
push hl \ pop bc
|
|
pop hl ; <-- lvl 1
|
|
; Good! BC done. Now, let's adjust BUF_LINECNT by DE-HL
|
|
push hl ; --> lvl 1
|
|
scf \ ccf
|
|
sbc hl, de ; HL -> nb of lines to delete, negative
|
|
push de ; --> lvl 2
|
|
ld de, (BUF_LINECNT)
|
|
add hl, de ; adding DE to negative HL
|
|
ld (BUF_LINECNT), hl
|
|
pop de ; <-- lvl 2
|
|
pop hl ; <-- lvl 1
|
|
; Line count updated!
|
|
; One other thing... is BC zero? Because if it is, then we shouldn't
|
|
; call ldir (otherwise we're on for a veeeery long loop), BC=0 means
|
|
; that only last lines were deleted. nothing to do.
|
|
ld a, b
|
|
or c
|
|
ret z ; BC==0, return
|
|
|
|
; let's have invert HL and DE to match LDIR's signature
|
|
ex de, hl
|
|
; At this point we have higher index in HL, lower index in DE and number
|
|
; of bytes to delete in BC. It's convenient because it's rather close
|
|
; to LDIR's signature! The only thing we need to do now is to translate
|
|
; those HL and DE indexes in memory addresses, that is, multiply by 2
|
|
; and add BUF_LINES
|
|
push hl ; --> lvl 1
|
|
ex de, hl
|
|
call bufLineAddr
|
|
ex de, hl
|
|
pop hl ; <-- lvl 1
|
|
call bufLineAddr
|
|
; Both HL and DE are translated. Go!
|
|
ldir
|
|
ret
|
|
|
|
; Insert string where DE points to memory scratchpad, then insert that line
|
|
; at index HL, offsetting all lines by 2 bytes.
|
|
bufInsertLine:
|
|
call bufIndexInBounds
|
|
jr nz, .append
|
|
push de ; --> lvl 1, scratchpad ptr
|
|
push hl ; --> lvl 2, insert index
|
|
; The logic below is mostly copy-pasted from bufDelLines, but with a
|
|
; LDDR logic (to avoid overwriting). I learned, with some pain involved,
|
|
; that generalizing this code wasn't working very well. I don't repeat
|
|
; the comments, refer to bufDelLines
|
|
ex de, hl ; line index now in DE
|
|
ld hl, (BUF_LINECNT)
|
|
scf \ ccf
|
|
sbc hl, de
|
|
; mult by 2 and we're done
|
|
sla l \ rl h
|
|
push hl \ pop bc
|
|
; From this point, we don't need our line index in DE any more because
|
|
; LDDR will start from BUF_LINECNT-1 with count BC. We'll only need it
|
|
; when it's time to insert the line in the space we make.
|
|
ld hl, (BUF_LINECNT)
|
|
call bufLineAddr
|
|
; HL is pointing to *first byte* after last line. Our source needs to
|
|
; be the second byte of the last line and our dest is the second byte
|
|
; after the last line.
|
|
push hl \ pop de
|
|
dec hl ; second byte of last line
|
|
inc de ; second byte beyond last line
|
|
; HL = BUF_LINECNT-1, DE = BUF_LINECNT, BC is set. We're good!
|
|
lddr
|
|
.set:
|
|
; We still need to increase BUF_LINECNT
|
|
ld hl, (BUF_LINECNT)
|
|
inc hl
|
|
ld (BUF_LINECNT), hl
|
|
; A space has been opened at line index HL. Let's fill it with our
|
|
; inserted line.
|
|
pop hl ; <-- lvl 2, insert index
|
|
call bufLineAddr
|
|
pop de ; <-- lvl 1, scratchpad offset
|
|
ld (hl), e
|
|
inc hl
|
|
ld (hl), d
|
|
ret
|
|
.append:
|
|
; nothing to move, just put the line there. Let's piggy-back on the end
|
|
; of the regular routine by carefully pushing the right register in the
|
|
; right place.
|
|
; But before that, make sure that HL isn't too high. The only place we
|
|
; can append to is at (BUF_LINECNT)
|
|
ld hl, (BUF_LINECNT)
|
|
push de ; --> lvl 1
|
|
push hl ; --> lvl 2
|
|
jr .set
|
|
|
|
; copy string that HL points to to scratchpad and return its pointer in
|
|
; scratchpad, in HL.
|
|
bufScratchpadAdd:
|
|
push de
|
|
ld de, (BUF_PADEND)
|
|
push de ; --> lvl 1
|
|
call strcpyM
|
|
inc de ; pad end is last char + 1
|
|
ld (BUF_PADEND), de
|
|
pop hl ; <-- lvl 1
|
|
pop de
|
|
ret
|
|
|
|
; Sets Z according to whether the line index in HL is within bounds.
|
|
bufIndexInBounds:
|
|
push de
|
|
ld de, (BUF_LINECNT)
|
|
call cpHLDE
|
|
pop de
|
|
jr c, .withinBounds
|
|
; out of bounds
|
|
jp unsetZ
|
|
.withinBounds:
|
|
cp a ; ensure Z
|
|
ret
|