rulimine/stage23/lib/term.s2.c
2021-06-08 00:06:33 +02:00

274 lines
7.2 KiB
C

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <lib/term.h>
#include <lib/real.h>
#include <lib/image.h>
#include <lib/blib.h>
#include <drivers/vga_textmode.h>
// Tries to implement this standard for terminfo
// https://man7.org/linux/man-pages/man4/console_codes.4.html
#define TERM_TABSIZE (8)
#define MAX_ESC_VALUES (256)
int current_video_mode = -1;
int term_backend = NOT_READY;
void (*raw_putchar)(uint8_t c);
void (*clear)(bool move);
void (*enable_cursor)(void);
bool (*disable_cursor)(void);
void (*set_cursor_pos)(int x, int y);
void (*get_cursor_pos)(int *x, int *y);
void (*set_text_fg)(int fg);
void (*set_text_bg)(int bg);
void (*term_double_buffer)(bool status);
void (*term_double_buffer_flush)(void);
int term_rows, term_cols;
#if defined (bios)
void term_textmode(void) {
term_backend = NOT_READY;
init_vga_textmode(&term_rows, &term_cols, true);
raw_putchar = text_putchar;
clear = text_clear;
enable_cursor = text_enable_cursor;
disable_cursor = text_disable_cursor;
set_cursor_pos = text_set_cursor_pos;
get_cursor_pos = text_get_cursor_pos;
set_text_fg = text_set_text_fg;
set_text_bg = text_set_text_bg;
term_double_buffer = text_double_buffer;
term_double_buffer_flush = text_double_buffer_flush;
term_backend = TEXTMODE;
}
#endif
void term_deinit(void) {
term_backend = NOT_READY;
}
static void term_putchar(uint8_t c);
void term_write(const char *buf, size_t count) {
if (term_backend == NOT_READY)
return;
bool old_cur_stat = disable_cursor();
for (size_t i = 0; i < count; i++)
term_putchar(buf[i]);
if (old_cur_stat)
enable_cursor();
}
static int get_cursor_pos_x(void) {
int x, y;
get_cursor_pos(&x, &y);
return x;
}
static int get_cursor_pos_y(void) {
int x, y;
get_cursor_pos(&x, &y);
return y;
}
static bool control_sequence = false;
static bool escape = false;
static bool rrr = false;
static int esc_values[MAX_ESC_VALUES];
static int esc_values_i = 0;
static int saved_cursor_x = 0, saved_cursor_y = 0;
static void sgr(void) {
int i = 0;
if (!esc_values_i)
goto def;
for (; i < esc_values_i; i++) {
if (!esc_values[i]) {
def:
set_text_bg(8);
set_text_fg(9);
continue;
}
if (esc_values[i] >= 30 && esc_values[i] <= 37) {
set_text_fg(esc_values[i] - 30);
continue;
}
if (esc_values[i] >= 40 && esc_values[i] <= 47) {
set_text_bg(esc_values[i] - 40);
continue;
}
}
}
static void control_sequence_parse(uint8_t c) {
if (c >= '0' && c <= '9') {
rrr = true;
esc_values[esc_values_i] *= 10;
esc_values[esc_values_i] += c - '0';
return;
} else {
if (rrr == true) {
esc_values_i++;
rrr = false;
if (c == ';')
return;
} else if (c == ';') {
esc_values[esc_values_i] = 1;
esc_values_i++;
return;
}
}
// default rest to 1
for (int i = esc_values_i; i < MAX_ESC_VALUES; i++)
esc_values[i] = 1;
switch (c) {
case 'A':
if (esc_values[0] > get_cursor_pos_y())
esc_values[0] = get_cursor_pos_y();
set_cursor_pos(get_cursor_pos_x(), get_cursor_pos_y() - esc_values[0]);
break;
case 'B':
if ((get_cursor_pos_y() + esc_values[0]) > (term_rows - 1))
esc_values[0] = (term_rows - 1) - get_cursor_pos_y();
set_cursor_pos(get_cursor_pos_x(), get_cursor_pos_y() + esc_values[0]);
break;
case 'C':
if ((get_cursor_pos_x() + esc_values[0]) > (term_cols - 1))
esc_values[0] = (term_cols - 1) - get_cursor_pos_x();
set_cursor_pos(get_cursor_pos_x() + esc_values[0], get_cursor_pos_y());
break;
case 'D':
if (esc_values[0] > get_cursor_pos_x())
esc_values[0] = get_cursor_pos_x();
set_cursor_pos(get_cursor_pos_x() - esc_values[0], get_cursor_pos_y());
break;
case 'E':
if (get_cursor_pos_y() + esc_values[0] >= term_rows)
set_cursor_pos(0, term_rows - 1);
else
set_cursor_pos(0, get_cursor_pos_y() + esc_values[0]);
break;
case 'F':
if (get_cursor_pos_y() - esc_values[0] < 0)
set_cursor_pos(0, 0);
else
set_cursor_pos(0, get_cursor_pos_y() - esc_values[0]);
break;
case 'd':
if (esc_values[0] >= term_rows)
break;
set_cursor_pos(get_cursor_pos_x(), esc_values[0]);
break;
case 'G':
case '`':
if (esc_values[0] >= term_cols)
break;
set_cursor_pos(esc_values[0], get_cursor_pos_y());
break;
case 'H':
case 'f':
esc_values[0] -= 1;
esc_values[1] -= 1;
if (esc_values[1] >= term_cols)
esc_values[1] = term_cols - 1;
if (esc_values[0] >= term_rows)
esc_values[0] = term_rows - 1;
set_cursor_pos(esc_values[1], esc_values[0]);
break;
case 'J':
switch (esc_values[0]) {
case 2:
clear(false);
break;
default:
break;
}
break;
case 'm':
sgr();
break;
case 's':
get_cursor_pos(&saved_cursor_x, &saved_cursor_y);
break;
case 'u':
set_cursor_pos(saved_cursor_x, saved_cursor_y);
break;
case 'K':
switch (esc_values[0]) {
case 2: {
int x, y;
get_cursor_pos(&x, &y);
set_cursor_pos(0, y);
for (int i = 0; i < term_cols; i++)
raw_putchar(' ');
set_cursor_pos(x, y);
break;
}
}
default:
break;
}
control_sequence = false;
escape = false;
}
static void escape_parse(uint8_t c) {
if (control_sequence == true) {
control_sequence_parse(c);
return;
}
switch (c) {
case '[':
for (int i = 0; i < MAX_ESC_VALUES; i++)
esc_values[i] = 0;
esc_values_i = 0;
rrr = false;
control_sequence = true;
break;
default:
escape = false;
break;
}
}
static void term_putchar(uint8_t c) {
if (escape == true) {
escape_parse(c);
return;
}
switch (c) {
case '\0':
break;
case '\e':
escape = 1;
return;
case '\t':
if ((get_cursor_pos_x() / TERM_TABSIZE + 1) >= term_cols)
break;
set_cursor_pos((get_cursor_pos_x() / TERM_TABSIZE + 1) * TERM_TABSIZE, get_cursor_pos_y());
break;
default:
raw_putchar(c);
break;
}
}