1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-01 23:30:56 +11:00
collapseos/apps/ed/main.asm
Virgil Dupras 7cf3ed38da Extract str.asm from core.asm and make core included by userspace
Most of register fiddling routines (which is now the only thing contained
in care.asm) are used by almost all userspace apps, often in inner loops.

That makes the penalty of using jump tables for those a bit too high.
Moreover, it burdens jump tables needlessly.

Because this unit is very small (now that string routines are out), it makes
sense to always include it in binaries.
2019-11-14 10:14:15 -05:00

177 lines
3.6 KiB
NASM

; ed - line editor
;
; A text editor modeled after UNIX's ed, but simpler. The goal is to stay tight
; on resources and to avoid having to implement screen management code (that is,
; develop the machinery to have ncurses-like apps in Collapse OS).
;
; ed has a mechanism to avoid having to move a lot of memory around at each
; edit. Each line is an element in an doubly-linked list and each element point
; to an offset in the "scratchpad". The scratchpad starts with the file
; contents and every time we change or add a line, that line goes to the end of
; the scratch pad and linked lists are reorganized whenever lines are changed.
; Contents itself is always appended to the scratchpad.
;
; That's on a resourceful UNIX system.
;
; That doubly linked list on the z80 would use 7 bytes per line (prev, next,
; offset, len), which is a bit much.
;
; We sacrifice speed for memory usage by making that linked list into a simple
; array of pointers to line contents in scratchpad. This means that we
; don't have an easy access to line length and we have to move a lot of memory
; around whenever we add or delete lines. Hopefully, "LDIR" will be our friend
; here...
;
; *** Variables ***
;
.equ ED_CURLINE ED_RAMSTART
.equ ED_RAMEND @+2
edMain:
; because ed only takes a single string arg, we can use HL directly
call ioInit
ret nz
; diverge from UNIX: start at first line
ld hl, 0
ld (ED_CURLINE), hl
call bufInit
.mainLoop:
ld a, ':'
call stdioPutC
call stdioReadLine ; --> HL
; Now, process line.
call printcrlf
call cmdParse
jp nz, .error
ld a, (CMD_TYPE)
cp 'q'
jr z, .doQ
cp 'w'
jr z, .doW
; The rest of the commands need an address
call edReadAddrs
jr nz, .error
ld a, (CMD_TYPE)
cp 'i'
jr z, .doI
; The rest of the commands don't allow addr == cnt
push hl ; --> lvl 1
ld hl, (BUF_LINECNT)
call cpHLDE
pop hl ; <-- lvl 1
jr z, .error
ld a, (CMD_TYPE)
cp 'd'
jr z, .doD
cp 'a'
jr z, .doA
jr .doP
.doQ:
xor a
ret
.doW:
ld a, 3 ; seek beginning
call ioSeek
ld de, 0 ; cur line
.wLoop:
push de \ pop hl
call bufGetLine ; --> buffer in (HL)
jr nz, .wEnd
call ioPutLine
jr nz, .error
inc de
jr .wLoop
.wEnd:
; Set new file size
call ioTell
call ioSetSize
; for now, writing implies quitting
; TODO: reload buffer
xor a
ret
.doD:
ld (ED_CURLINE), de
; bufDelLines expects an exclusive upper bound, which is why we inc DE.
inc de
call bufDelLines
jr .mainLoop
.doA:
inc de
.doI:
call stdioReadLine ; --> HL
call bufScratchpadAdd ; --> HL
; insert index in DE, line offset in HL. We want the opposite.
ex de, hl
ld (ED_CURLINE), hl
call bufInsertLine
call printcrlf
jr .mainLoop
.doP:
push hl
call bufGetLine
jr nz, .error
call printstr
call printcrlf
pop hl
call cpHLDE
jr z, .doPEnd
inc hl
jr .doP
.doPEnd:
ld (ED_CURLINE), hl
jp .mainLoop
.error:
ld a, '?'
call stdioPutC
call printcrlf
jp .mainLoop
; Transform an address "cmd" in IX into an absolute address in HL.
edResolveAddr:
ld a, (ix)
cp RELATIVE
jr z, .relative
cp EOF
jr z, .eof
; absolute
ld l, (ix+1)
ld h, (ix+2)
ret
.relative:
ld hl, (ED_CURLINE)
push de
ld e, (ix+1)
ld d, (ix+2)
add hl, de
pop de
ret
.eof:
ld hl, (BUF_LINECNT)
dec hl
ret
; Read absolute addr1 in HL and addr2 in DE. Also, check bounds and set Z if
; both addresses are within bounds, unset if not.
edReadAddrs:
ld ix, CMD_ADDR2
call edResolveAddr
ld de, (BUF_LINECNT)
ex de, hl ; HL: cnt DE: addr2
call cpHLDE
jp c, unsetZ ; HL (cnt) < DE (addr2). no good
ld ix, CMD_ADDR1
call edResolveAddr
ex de, hl ; HL: addr2, DE: addr1
call cpHLDE
jp c, unsetZ ; HL (addr2) < DE (addr1). no good
ex de, hl ; HL: addr1, DE: addr2
cp a ; ensure Z
ret