1a5a1b9861
The dual scraptchpad thing doesn't work. Things become very complicated when it's time to write that back to the file. We overwrite our contents and end up with garbage.
181 lines
4.6 KiB
NASM
181 lines
4.6 KiB
NASM
; buf - manage line buffer
|
|
;
|
|
; *** Consts ***
|
|
;
|
|
; Maximum number of lines allowed in the buffer.
|
|
.equ BUF_MAXLINES 0x800
|
|
; Size of our scratchpad
|
|
.equ BUF_PADMAXLEN 0x1000
|
|
|
|
; *** Variables ***
|
|
; Number of lines currently in the buffer
|
|
.equ BUF_LINECNT BUF_RAMSTART
|
|
; List of pointers to strings in scratchpad
|
|
.equ BUF_LINES BUF_LINECNT+2
|
|
; Points to the end of the scratchpad, that is, one byte after the last written
|
|
; char in it.
|
|
.equ BUF_PADEND BUF_LINES+BUF_MAXLINES*2
|
|
; The in-memory scratchpad
|
|
.equ BUF_PAD BUF_PADEND+2
|
|
|
|
.equ BUF_RAMEND BUF_PAD+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
|
|
.loop:
|
|
call ioGetC
|
|
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!
|
|
; 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:
|
|
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
|
|
push hl \ pop de
|
|
dec hl
|
|
dec hl
|
|
; HL = BUF_LINECNT-1, DE = BUF_LINECNT, BC is set. We're good!
|
|
lddr
|
|
; 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
|
|
|
|
; 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
|