collapseos/apps/ed/main.asm

177 lines
3.6 KiB
NASM
Raw Normal View History

2019-07-13 23:57:37 +10:00
; 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,
2019-10-05 03:49:33 +10:00
; offset, len), which is a bit much.
2019-07-13 23:57:37 +10:00
;
; 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
2019-07-13 23:57:37 +10:00
; 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
2019-07-13 23:57:37 +10:00
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
2019-07-15 02:19:37 +10:00
call bufInit
2019-07-14 01:29:06 +10:00
.mainLoop:
2019-07-14 04:01:20 +10:00
ld a, ':'
call stdioPutC
2019-07-15 07:29:00 +10:00
call stdioReadLine ; --> HL
; Now, process line.
2019-07-13 23:57:37 +10:00
call printcrlf
2019-07-14 11:08:16 +10:00
call cmdParse
2019-07-22 09:32:24 +10:00
jp nz, .error
2019-07-14 23:04:51 +10:00
ld a, (CMD_TYPE)
2019-07-13 23:57:37 +10:00
cp 'q'
2019-07-22 05:06:03 +10:00
jr z, .doQ
2019-07-22 01:39:00 +10:00
cp 'w'
2019-07-22 05:06:03 +10:00
jr z, .doW
2019-07-15 07:29:00 +10:00
; The rest of the commands need an address
call edReadAddrs
jr nz, .error
ld a, (CMD_TYPE)
2019-07-22 05:06:03 +10:00
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
2019-07-22 09:32:24 +10:00
ld a, (CMD_TYPE)
2019-07-15 00:32:28 +10:00
cp 'd'
2019-07-22 05:06:03 +10:00
jr z, .doD
2019-07-15 07:29:00 +10:00
cp 'a'
2019-07-22 05:06:03 +10:00
jr z, .doA
jr .doP
2019-07-14 11:08:16 +10:00
2019-07-22 05:06:03 +10:00
.doQ:
2019-07-14 23:04:51 +10:00
xor a
ret
2019-07-15 00:32:28 +10:00
2019-07-22 05:06:03 +10:00
.doW:
2019-07-22 01:39:00 +10:00
ld a, 3 ; seek beginning
call ioSeek
ld de, 0 ; cur line
2019-07-22 05:06:03 +10:00
.wLoop:
2019-07-22 01:39:00 +10:00
push de \ pop hl
call bufGetLine ; --> buffer in (HL)
2019-07-22 05:06:03 +10:00
jr nz, .wEnd
2019-07-22 01:39:00 +10:00
call ioPutLine
jr nz, .error
inc de
2019-07-22 05:06:03 +10:00
jr .wLoop
.wEnd:
2019-07-22 01:39:00 +10:00
; Set new file size
call ioTell
call ioSetSize
; for now, writing implies quitting
; TODO: reload buffer
xor a
ret
2019-07-22 05:06:03 +10:00
.doD:
2019-07-26 11:24:36 +10:00
ld (ED_CURLINE), de
2019-07-15 00:32:28 +10:00
; bufDelLines expects an exclusive upper bound, which is why we inc DE.
inc de
call bufDelLines
jr .mainLoop
2019-07-22 05:06:03 +10:00
.doA:
2019-07-15 07:29:00 +10:00
inc de
2019-07-22 05:06:03 +10:00
.doI:
2019-07-15 07:29:00 +10:00
call stdioReadLine ; --> HL
call bufScratchpadAdd ; --> HL
; insert index in DE, line offset in HL. We want the opposite.
ex de, hl
2019-07-26 11:24:36 +10:00
ld (ED_CURLINE), hl
2019-07-15 07:29:00 +10:00
call bufInsertLine
call printcrlf
jr .mainLoop
2019-07-22 05:06:03 +10:00
.doP:
2019-07-14 12:09:17 +10:00
push hl
2019-07-14 04:01:20 +10:00
call bufGetLine
2019-07-14 11:08:16 +10:00
jr nz, .error
call printstr
call printcrlf
2019-07-14 12:09:17 +10:00
pop hl
call cpHLDE
2019-07-22 05:06:03 +10:00
jr z, .doPEnd
2019-07-14 12:09:17 +10:00
inc hl
2019-07-22 05:06:03 +10:00
jr .doP
.doPEnd:
2019-07-14 23:04:51 +10:00
ld (ED_CURLINE), hl
2019-07-22 01:39:00 +10:00
jp .mainLoop
2019-07-14 11:08:16 +10:00
.error:
2019-07-14 04:01:20 +10:00
ld a, '?'
call stdioPutC
call printcrlf
2019-07-22 01:39:00 +10:00
jp .mainLoop
2019-07-14 04:01:20 +10:00
2019-07-14 11:08:16 +10:00
; Transform an address "cmd" in IX into an absolute address in HL.
edResolveAddr:
ld a, (ix)
cp RELATIVE
jr z, .relative
2019-10-05 03:49:33 +10:00
cp EOF
jr z, .eof
2019-07-14 11:08:16 +10:00
; absolute
ld l, (ix+1)
ld h, (ix+2)
ret
2019-07-14 11:08:16 +10:00
.relative:
ld hl, (ED_CURLINE)
2019-07-14 12:09:17 +10:00
push de
2019-07-14 11:08:16 +10:00
ld e, (ix+1)
ld d, (ix+2)
add hl, de
2019-07-14 12:09:17 +10:00
pop de
ret
2019-10-05 03:49:33 +10:00
.eof:
ld hl, (BUF_LINECNT)
dec hl
ret
2019-07-14 23:04:51 +10:00
; 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
2019-07-22 05:06:03 +10:00
ld de, (BUF_LINECNT)
ex de, hl ; HL: cnt DE: addr2
2019-07-14 23:04:51 +10:00
call cpHLDE
2019-07-22 05:06:03 +10:00
jp c, unsetZ ; HL (cnt) < DE (addr2). no good
2019-07-14 23:04:51 +10:00
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