|
- ; 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
|