stdio: add stdioReadC

A routine to conveniently read lines from TTY. Extracted from
shell. Will be used in other places.
This commit is contained in:
Virgil Dupras 2019-07-13 09:19:01 -04:00
parent 252d71f1b8
commit e01ee170cb
2 changed files with 114 additions and 81 deletions

View File

@ -35,10 +35,6 @@
; number of entries in shellCmdTbl
.equ SHELL_CMD_COUNT 6+SHELL_EXTRA_CMD_COUNT
; Size of the shell command buffer. If a typed command reaches this size, the
; command is flushed immediately (same as pressing return).
.equ SHELL_BUFSIZE 0x20
; *** VARIABLES ***
; Memory address that the shell is currently "pointing at" for peek, load, call
; operations. Set with mptr.
@ -48,13 +44,8 @@
; written to after parsing.
.equ SHELL_CMD_ARGS SHELL_MEM_PTR+2
; Command buffer. We read types chars into this buffer until return is pressed
; This buffer is null-terminated and we don't keep an index around: we look
; for the null-termination every time we write to it. Simpler that way.
.equ SHELL_BUF SHELL_CMD_ARGS+PARSE_ARG_MAXCOUNT
; Pointer to a hook to call when a cmd name isn't found
.equ SHELL_CMDHOOK SHELL_BUF+SHELL_BUFSIZE
.equ SHELL_CMDHOOK SHELL_CMD_ARGS+PARSE_ARG_MAXCOUNT
; Pointer to a routine to call at each shell loop interation
.equ SHELL_LOOPHOOK SHELL_CMDHOOK+2
@ -65,14 +56,13 @@ shellInit:
xor a
ld (SHELL_MEM_PTR), a
ld (SHELL_MEM_PTR+1), a
ld (SHELL_BUF), a
ld hl, noop
ld (SHELL_CMDHOOK), hl
ld (SHELL_LOOPHOOK), hl
; print welcome
ld hl, .welcome
jp printstr ; returns
jp printstr
.welcome:
.db "Collapse OS", ASCII_CR, ASCII_LF, "> ", 0
@ -84,52 +74,12 @@ shellLoop:
ld ix, (SHELL_LOOPHOOK)
call callIX
; Then, let's wait until something is typed.
call stdioGetC
jr nz, shellLoop ; nothing typed? loop
; got it. Now, is it a CR or LF?
cp ASCII_CR
jr z, .do ; char is CR? do!
cp ASCII_LF
jr z, .do ; char is LF? do!
cp ASCII_DEL
jr z, .delchr
cp ASCII_BS
jr z, .delchr
; Echo the received character right away so that we see what we type
call stdioPutC
; Ok, gotta add it do the buffer
; save char for later
ex af, af'
ld hl, SHELL_BUF
xor a ; look for null
call findchar ; HL points to where we need to write
; A is the number of chars in the buf
cp SHELL_BUFSIZE-1 ; -1 is because we always want to keep our
; last char at zero.
jr z, .do ; end of buffer reached? buffer is full. do!
; bring the char back in A
ex af, af'
; Buffer not full, not CR or LF. Let's put that char in our buffer and
; read again.
ld (hl), a
; Now, write a zero to the next byte to properly terminate our string.
inc hl
xor a
ld (hl), a
jr shellLoop
.do:
call stdioReadC
jr nz, shellLoop ; not done? loop
; We're done. Process line.
call printcrlf
ld hl, SHELL_BUF
call stdioGetLine
call shellParse
; empty our buffer by writing a zero to its first char
xor a
ld (hl), a
ld hl, .prompt
call printstr
jr shellLoop
@ -137,28 +87,6 @@ shellLoop:
.prompt:
.db "> ", 0
.delchr:
ld hl, SHELL_BUF
ld a, (hl)
or a ; cp 0
jr z, shellLoop ; buffer empty? nothing to do
; buffer not empty, let's delete
xor a ; look for null
call findchar ; HL points to end of buf
dec hl ; the char before it
xor a
ld (hl), a ; set to zero
; Char deleted in buffer, now send BS + space + BS for the terminal
; to clear its previous char
ld a, ASCII_BS
call stdioPutC
ld a, ' '
call stdioPutC
ld a, ASCII_BS
call stdioPutC
jr shellLoop
; Parse command (null terminated) at HL and calls it
shellParse:
push af

View File

@ -1,20 +1,36 @@
; stdio
;
; Allows other modules to print to "standard out", and get data from "stamdard
; Allows other modules to print to "standard out", and get data from "standard
; in", that is, the console through which the user is connected in a decoupled
; manner.
;
; *** VARIABLES ***
; *** Consts ***
; Size of the readline buffer. If a typed line reaches this size, the line is
; flushed immediately (same as pressing return).
.equ STDIO_BUFSIZE 0x20
; *** Variables ***
; Used to store formatted hex values just before printing it.
.equ STDIO_HEX_FMT STDIO_RAMSTART
.equ STDIO_GETC STDIO_HEX_FMT+2
.equ STDIO_PUTC STDIO_GETC+2
.equ STDIO_RAMEND STDIO_PUTC+2
; Line buffer. We read types chars into this buffer until return is pressed
; This buffer is null-terminated and we don't keep an index around: we look
; for the null-termination every time we write to it. Simpler that way.
.equ STDIO_BUF STDIO_PUTC+2
; Index where the next char will go in stdioGetC.
.equ STDIO_BUFIDX STDIO_BUF+STDIO_BUFSIZE
.equ STDIO_RAMEND STDIO_BUFIDX+1
; Sets GetC to the routine where HL points to and PutC to DE.
stdioInit:
ld (STDIO_GETC), hl
ld (STDIO_PUTC), de
xor a
ld (STDIO_BUF), a
ld (STDIO_BUFIDX), a
ret
stdioGetC:
@ -88,3 +104,92 @@ printHexPair:
call printHex
pop af
ret
; Call stdioGetC and put the result in the buffer. Sets Z according to whether
; the buffer is "complete", that is, whether CR or LF have been pressed or if
; the the buffer is full. Z is set if the line is "complete", unset if not.
; The next call to stdioReadC after a completed line will start a new line.
;
; This routine also takes care of echoing received characters back to the TTY.
;
; Note that this routine doesn't bother returning the typed character.
stdioReadC:
; Let's wait until something is typed.
call stdioGetC
jr nz, stdioReadC ; nothing typed? loop
; got it. Now, is it a CR or LF?
cp ASCII_CR
jr z, .complete ; char is CR? buffer complete!
cp ASCII_LF
jr z, .complete
cp ASCII_DEL
jr z, .delchr
cp ASCII_BS
jr z, .delchr
; Echo the received character right away so that we see what we type
call stdioPutC
; Ok, gotta add it do the buffer
; save char for later
ex af, af'
ld a, (STDIO_BUFIDX)
push hl ;<|
ld hl, STDIO_BUF ; |
; make HL point to dest spot |
call addHL ; |
; Write our char down |
ex af, af' ; |
ld (hl), a ; |
; follow up with a null char |
inc hl ; |
xor a ; |
ld (hl), a ; |
pop hl ;<|
; inc idx, which still is in AF'
ex af, af'
inc a
cp STDIO_BUFSIZE-1 ; -1 is because we always want to keep our
; last char at zero.
jr z, .complete ; end of buffer reached? buffer is full.
; not complete. save idx back
ld (STDIO_BUFIDX), a
; Z already unset
ret
.complete:
; The line in our buffer is complete.
xor a ; sets Z
ld (STDIO_BUFIDX), a
ret
.delchr:
ld a, (STDIO_BUFIDX)
or a
jp z, unsetZ ; buf empty? nothing to do
; buffer not empty, let's go back one char and set a null char there.
dec a
ld (STDIO_BUFIDX), a
push hl ;<|
ld hl, STDIO_BUF ; |
; make HL point to dest spot |
call addHL ; |
xor a ; |
ld (hl), a ; |
pop hl ;<|
; Char deleted in buffer, now send BS + space + BS for the terminal
; to clear its previous char
ld a, ASCII_BS
call stdioPutC
ld a, ' '
call stdioPutC
ld a, ASCII_BS
call stdioPutC
jp unsetZ
; Make HL point to the line buffer. It is always null terminated.
stdioGetLine:
ld hl, STDIO_BUF
ret