A routine to conveniently read lines from TTY. Extracted from shell. Will be used in other places.pull/10/head
@@ -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 | |||
@@ -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 |