Vhex-kernel/src/kernel/devices/tty/file_op/write.c

190 lines
3.8 KiB
C

#include <kernel/devices/tty.h>
#include <kernel/devices/display.h>
#include <kernel/util/atomic.h>
#include <kernel/util/debug.h>
#include <kernel/util/string.h>
// Internal TTY object.
extern struct tty_s tty;
static void tty_vertical_update(void)
{
// Get next line.
tty.cursor.y =
(tty.cursor.y + 1 <= tty.cursor.max.y)
? tty.cursor.y + 1
: 0;
// Wipe new line.
memset(tty.buffer[tty.cursor.y], '\0', tty.cursor.max.x);
}
static int tty_horizontal_update(void)
{
tty.cursor.x = tty.cursor.x + 1;
if (tty.cursor.x >= tty.cursor.max.x)
{
tty_vertical_update();
tty.cursor.x = 0;
return (1);
}
return (0);
}
// Line discipline :D
static ssize_t tty_buffer_update(const uint8_t *buffer, size_t count)
{
int16_t offset;
ssize_t i;
i = -1;
while (++i < (ssize_t)count)
{
// Check bell char.
if (buffer[i] == '\a')
{
// TODO
continue;
}
// Check backspace.
if (buffer[i] == '\b')
{
if (tty.cursor.x > 0)
tty.cursor.x = tty.cursor.x - 1;
tty.buffer[tty.cursor.y][tty.cursor.x] = '\0';
continue;
}
// Check horizotal tab.
if (buffer[i] == '\t')
{
// Check if we need a new line or not.
offset = 5 - (tty.cursor.x - ((tty.cursor.x / 5) * 5));
if (tty.cursor.x + offset < tty.cursor.max.x)
{
memset(&tty.buffer[tty.cursor.y][tty.cursor.x], ' ', offset);
tty.cursor.x = tty.cursor.x + offset;
continue;
}
// If a new line is required char.
// Generate a new line.
tty.cursor.x = 0;
tty_vertical_update();
continue;
}
// Check new line char.
if (buffer[i] == '\n')
{
tty.cursor.x = 0;
tty_vertical_update();
continue;
}
// Check 'form feed' and 'vertical tab' char.
// @note: for now this character is interpreted like '\v'
if (buffer[i] == '\f' || buffer[i] == '\v')
{
tty_vertical_update();
memset(tty.buffer[tty.cursor.y], ' ', tty.cursor.x);
continue;
}
// Check carriage return.
if (buffer[i] == '\r') { tty.cursor.x = 0; continue;}
// Update TTY buffer char.
tty.buffer[tty.cursor.y][tty.cursor.x] = buffer[i];
tty_horizontal_update();
}
return (i);
}
// FIXME: this function is device-specific !
// TODO: Update me ?
static void tty_display(void)
{
int saved_start;
int line_len;
int scolumn;
int srow;
int line;
int start;
int i;
// Start atomic operation.
atomic_start();
// Save display "context".
display_ioctl(DISPLAY_IOCTL_GETY, &srow);
display_ioctl(DISPLAY_IOCTL_GETX, &scolumn);
// Clear Display
// TODO: IOCTL to disable auto put on screen.
display_ioctl(DISPLAY_IOCTL_CLEAR);
// Get the "first" line and number of line.
// @note: circular buffer.
line = 0;
start = tty.cursor.y;
while (++line < DISPLAY_VCHAR_MAX)
{
// Update check line.
saved_start = start;
start = (start - 1 < 0) ? tty.cursor.max.y : start - 1;
// Check if the line existe.
if (tty.buffer[start][0] == '\0')
{
start = saved_start;
break;
}
}
// Display "on-screen" string lines.
i = -1;
while (++i < line)
{
// Set display cursor.
display_ioctl(DISPLAY_IOCTL_SETX, 0);
display_ioctl(DISPLAY_IOCTL_SETY, i);
// Get / check line lenght.
line_len = strnlen(tty.buffer[start], tty.cursor.max.x);
if (line_len == 0)
continue;
// Display line.
tty.primitives.write(tty.buffer[start], line_len);
// Get "next" line.
start = (start + 1 > tty.cursor.max.y) ? 0 : start + 1;
}
// Display on screen.
display_ioctl(DISPLAY_IOCTL_DISPLAY);
// Restore display "context"
display_ioctl(DISPLAY_IOCTL_SETX, scolumn);
display_ioctl(DISPLAY_IOCTL_SETY, srow);
// End atomic operation
atomic_stop();
}
ssize_t tty_write(void *inode, const void *buffer, size_t count)
{
ssize_t written;
// Uopdate internal buffer and display
// TTY on the screen.
written = tty_buffer_update(buffer, count);
tty_display();
// Return the number of char written into
// TTY's internal buffer.
return (written);
}