rulimine/stage23/lib/term.s2.c

417 lines
12 KiB
C
Raw Normal View History

#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>
2021-05-23 01:19:27 +03:00
// Tries to implement this standard for terminfo
// https://man7.org/linux/man-pages/man4/console_codes.4.html
2021-05-23 00:11:18 +03:00
#define TERM_TABSIZE (8)
2021-05-23 01:19:27 +03:00
#define MAX_ESC_VALUES (256)
2021-05-23 00:11:18 +03:00
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);
2021-08-01 00:51:48 +03:00
void (*set_text_fg_bright)(int fg);
void (*set_text_bg_bright)(int bg);
void (*set_text_fg_default)(void);
void (*set_text_bg_default)(void);
bool (*scroll_disable)(void);
void (*scroll_enable)(void);
2021-07-31 21:52:46 +03:00
void (*term_move_character)(int new_x, int new_y, int old_x, int old_y);
void (*term_double_buffer)(bool status);
void (*term_double_buffer_flush)(void);
int term_rows, term_cols;
#if bios == 1
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;
2021-08-01 00:51:48 +03:00
set_text_fg_bright = text_set_text_fg;
set_text_bg_bright = text_set_text_bg;
set_text_fg_default = text_set_text_fg_default;
set_text_bg_default = text_set_text_bg_default;
scroll_disable = text_scroll_disable;
scroll_enable = text_scroll_enable;
2021-07-31 21:52:46 +03:00
term_move_character = text_move_character;
term_double_buffer = text_double_buffer;
term_double_buffer_flush = text_double_buffer_flush;
term_backend = TEXTMODE;
}
2021-03-02 12:23:43 +03:00
#endif
void term_deinit(void) {
term_backend = NOT_READY;
}
static void term_putchar(uint8_t c);
static bool old_cur_stat;
void term_write(const char *buf, size_t count) {
if (term_backend == NOT_READY)
return;
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;
}
2021-05-23 01:19:27 +03:00
static bool control_sequence = false;
static bool escape = false;
static bool rrr = false;
2021-07-31 21:52:46 +03:00
static bool dec_private = false;
static int32_t esc_values[MAX_ESC_VALUES];
static size_t esc_values_i = 0;
2021-05-23 01:19:27 +03:00
static int saved_cursor_x = 0, saved_cursor_y = 0;
2021-05-23 01:19:27 +03:00
static void sgr(void) {
2021-07-31 21:52:46 +03:00
size_t i = 0;
2021-05-23 01:19:27 +03:00
if (!esc_values_i)
goto def;
2021-05-23 01:19:27 +03:00
for (; i < esc_values_i; i++) {
if (!esc_values[i]) {
def:
2021-08-01 00:51:48 +03:00
set_text_bg_default();
set_text_fg_default();
2021-05-23 01:19:27 +03:00
continue;
}
2021-05-23 01:19:27 +03:00
if (esc_values[i] >= 30 && esc_values[i] <= 37) {
set_text_fg(esc_values[i] - 30);
continue;
}
2021-05-23 01:19:27 +03:00
if (esc_values[i] >= 40 && esc_values[i] <= 47) {
set_text_bg(esc_values[i] - 40);
continue;
}
2021-07-31 21:52:46 +03:00
2021-08-01 00:51:48 +03:00
if (esc_values[i] >= 90 && esc_values[i] <= 97) {
set_text_fg_bright(esc_values[i] - 90);
continue;
}
if (esc_values[i] >= 100 && esc_values[i] <= 107) {
set_text_bg_bright(esc_values[i] - 100);
continue;
}
2021-07-31 21:52:46 +03:00
if (esc_values[i] == 39) {
2021-08-01 00:51:48 +03:00
set_text_fg_default();
2021-07-31 21:52:46 +03:00
continue;
}
if (esc_values[i] == 49) {
2021-08-01 00:51:48 +03:00
set_text_bg_default();
2021-07-31 21:52:46 +03:00
continue;
}
}
}
2021-07-31 21:52:46 +03:00
static void dec_private_parse(uint8_t c) {
dec_private = false;
if (esc_values_i > 0) {
switch (esc_values[0]) {
case 25: {
switch (c) {
case 'h': old_cur_stat = true; return;
case 'l': old_cur_stat = false; return;
}
}
}
}
2021-07-31 21:52:46 +03:00
}
2021-05-23 01:19:27 +03:00
static void control_sequence_parse(uint8_t c) {
2021-07-31 21:52:46 +03:00
if (c == '?') {
dec_private = true;
return;
}
if (c >= '0' && c <= '9') {
2021-05-23 01:19:27 +03:00
rrr = true;
esc_values[esc_values_i] *= 10;
esc_values[esc_values_i] += c - '0';
return;
2021-05-23 01:19:27 +03:00
} 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;
}
}
2021-07-31 21:52:46 +03:00
int esc_default;
switch (c) {
case 'J': esc_default = 0; break;
case 'K': esc_default = 0; break;
default: esc_default = 1; break;
}
2021-05-23 01:19:27 +03:00
for (int i = esc_values_i; i < MAX_ESC_VALUES; i++)
2021-07-31 21:52:46 +03:00
esc_values[i] = esc_default;
if (dec_private == true) {
dec_private_parse(c);
goto cleanup;
}
2021-05-23 01:19:27 +03:00
switch (c) {
case 'A':
2021-05-23 01:19:27 +03:00
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':
2021-05-23 01:19:27 +03:00
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':
2021-05-23 01:19:27 +03:00
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':
2021-05-23 01:19:27 +03:00
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;
2021-05-23 01:19:27 +03:00
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;
2021-05-23 01:19:27 +03:00
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':
2021-05-23 01:19:27 +03:00
switch (esc_values[0]) {
2021-07-31 21:52:46 +03:00
case 0: {
int x, y;
get_cursor_pos(&x, &y);
int rows_remaining = term_rows - (y + 1);
int cols_diff = term_cols - (x + 1);
size_t to_clear = rows_remaining * term_cols + cols_diff;
bool r = scroll_disable();
for (size_t i = 0; i < to_clear; i++) {
raw_putchar(' ');
}
set_cursor_pos(x, y);
if (r)
scroll_enable();
break;
}
case 1: {
int x, y;
get_cursor_pos(&x, &y);
bool r = scroll_disable();
set_cursor_pos(0, 0);
bool b = false;
for (int yc = 0; yc < term_rows; yc++) {
for (int xc = 0; xc < term_cols; xc++) {
raw_putchar(' ');
if (xc == x && yc == y) {
raw_putchar('\b');
b = true;
break;
}
}
if (b == true)
break;
}
if (r)
scroll_enable();
break;
}
case 2:
clear(false);
break;
default:
break;
}
break;
2021-07-31 21:52:46 +03:00
case 'P': {
bool r = scroll_disable();
int x, y;
get_cursor_pos(&x, &y);
for (int i = x + esc_values[0]; i < term_cols; i++)
term_move_character(i - esc_values[0], y, i, y);
set_cursor_pos(term_cols - esc_values[0], y);
for (int i = 0; i < esc_values[0]; i++)
raw_putchar(' ');
set_cursor_pos(x, y);
if (r)
scroll_enable();
break;
}
2021-05-23 01:19:27 +03:00
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;
2021-07-31 21:52:46 +03:00
case 'K': {
bool r = scroll_disable();
int x, y;
get_cursor_pos(&x, &y);
2021-05-23 01:19:27 +03:00
switch (esc_values[0]) {
2021-07-31 21:52:46 +03:00
case 0: {
for (int i = x; i < term_cols; i++)
raw_putchar(' ');
set_cursor_pos(x, y);
break;
}
case 1: {
set_cursor_pos(0, y);
for (int i = 0; i < x; i++)
raw_putchar(' ');
break;
}
case 2: {
set_cursor_pos(0, y);
for (int i = 0; i < term_cols; i++)
raw_putchar(' ');
set_cursor_pos(x, y);
break;
}
}
2021-07-31 21:52:46 +03:00
if (r)
scroll_enable();
break;
}
2021-05-23 01:19:27 +03:00
default:
break;
}
2021-07-31 21:52:46 +03:00
cleanup:
2021-05-23 01:19:27 +03:00
control_sequence = false;
escape = false;
}
static void escape_parse(uint8_t c) {
if (control_sequence == true) {
control_sequence_parse(c);
return;
}
switch (c) {
case '\e':
escape = false;
raw_putchar(c);
break;
2021-05-23 01:19:27 +03:00
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:
2021-05-23 01:19:27 +03:00
escape = false;
break;
}
2021-05-23 01:19:27 +03:00
}
static void term_putchar(uint8_t c) {
if (escape == true) {
escape_parse(c);
return;
}
2021-05-23 01:19:27 +03:00
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;
2021-07-31 21:52:46 +03:00
case '\a':
break;
2021-05-23 01:19:27 +03:00
default:
raw_putchar(c);
break;
}
}