libc/newlib/libc/sys/sh3eb/console.c

167 lines
4.8 KiB
C

#include <sys/console.h>
#include <sys/casio_syscalls.h>
/*
* Console instance for printf etc.
*/
_console _console_ctx = {
.cursor_x = 0,
.cursor_y = 0,
.buf_strlen = 0,
.buf = {0},
};
/*
* Sets the internal cursor position on the console.
* Note that the Casio cursor position will not be set until
* the console is flushed (automatically or manually).
*/
void _console_set_cursor(_console *ctx, unsigned char x, unsigned char y) {
/*
* No need to flush here, because the buffer already was flushed
* at the end of the _console_write() function.
*/
if (x < _CONSOLE_WIDTH && y < _CONSOLE_HEIGHT) {
ctx->cursor_x = x;
ctx->cursor_y = y;
}
}
/*
* Writes the (potentially but not necessarily null-terminated)
* string *ptr to the internal buffer. May flush and invoke
* the Casio "locate" and "Print" syscalls.
*/
int _console_write (_console *ctx, int file, char *ptr, int len)
{
/*
* Start parsing
*/
while (len-- && *ptr) {
/*
* Filter out all control characters
*/
switch (*ptr) {
case '\a':
// ignore
ptr++;
continue;
case '\b':
// undo last char (if not first char in line)
// no wrapping
ctx->cursor_x -= !!ctx->cursor_x;
ctx->buf_strlen -= !!ctx->buf_strlen;
ctx->buf[ctx->buf_strlen] = '\0';
ptr++;
continue;
case '\f':
case '\v':
_console_flush(ctx);
ctx->cursor_y = (ctx->cursor_y + 1) % _CONSOLE_HEIGHT;
ptr++;
continue;
case '\n':
_console_flush(ctx);
ctx->cursor_x = 0;
ctx->cursor_y = (ctx->cursor_y + (ctx->cursor_x < _CONSOLE_WIDTH)) % _CONSOLE_HEIGHT;
ptr++;
continue;
case '\r':
_console_flush(ctx);
ctx->cursor_x = 0;
ptr++;
continue;
case '\t':
;
/*
* Go to next tab stop (or to the end of the line).
*/
/*
* Somehow the following statement (see int s) cannot be written directly inside
* the condition of the for loop (or the program will act strangely).
* Possibly due to signedness? TODO
*/
int s = _CONSOLE_TAB_LEN - (ctx->cursor_x % _CONSOLE_TAB_LEN);
for (int i = 0; i < s; i++) {
_console_write(ctx, file, " ", 1);
}
ptr++;
continue;
}
// Add char to the buffer (flushes before it overflows)
_console_putc(ctx, *ptr);
// Flush buffer if there is a line wrap
if (ctx->cursor_x == _CONSOLE_WIDTH - 1) {
/*
* Temporarily increment cursor_x (without wrapping)
* because _console_flush expects the cursor to point
* to the position of the next char.
*/
ctx->cursor_x++;
_console_flush(ctx);
ctx->cursor_x--;
}
// Move curser to the left (wrap if bounds are exceeded)
ctx->cursor_x = (ctx->cursor_x + 1) % _CONSOLE_WIDTH;
// Move curser down if (ctx->cursor_x == 0) (wrap if bounds are exceeded)
ctx->cursor_y = (ctx->cursor_y + !ctx->cursor_x) % _CONSOLE_HEIGHT;
ptr++;
}
// Always flush in the end
_console_flush(ctx);
return len;
}
/*
* Adds a character to the internal buffer.
* Does not take care of the cursor position.
* May invoke _console_flush() to print the contents of the internal buffer.
* Use _console_flush() to manually flush the contents to the console output.
* Does not change the position of the internal cursor.
*/
void _console_putc(_console *ctx, char c) {
if (ctx->buf_strlen == _CONSOLE_BUF_WIDTH - 1) {
_console_flush(ctx);
}
ctx->buf[ctx->buf_strlen++] = c;
ctx->buf[ctx->buf_strlen] = '\0';
}
/*
* Prints the buffer out to the console and invokes
* the Casio "locate" and "Print" syscalls.
* Resets the internal buffer to "".
* Does not change the position of the internal cursor.
*/
void _console_flush(_console *ctx) {
/*
* Local syscall to Casio's locate
* because Casio's syscall is overwritten by _casio_set_cursor()
*/
typedef void (*console_locate_type)(int, int);
static const unsigned int console_locate_address[] = { _CASIO_SYSCALLS_SCA, _CASIO_SYSCALLS_SCB,_CASIO_SYSCALLS_SCE, 0x807 };
static const console_locate_type console_locate_ptr = (console_locate_type) console_locate_address;
if (!ctx->buf_strlen) {
return;
}
// +1 because the CASIO cursor position is 1-based
console_locate_ptr(ctx->cursor_x - ctx->buf_strlen + 1, ctx->cursor_y + 1);
Print((unsigned char*) ctx->buf);
ctx->buf[0] = '\0';
ctx->buf_strlen = 0;
}