Upgrade ANSI parser
This commit is contained in:
parent
c5504b80dc
commit
641221c2bb
114
vga_drv/cansid.c
114
vga_drv/cansid.c
@ -1,114 +0,0 @@
|
|||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "cansid.h"
|
|
||||||
|
|
||||||
#define ESC '\x1B'
|
|
||||||
|
|
||||||
struct cansid_state cansid_init(void)
|
|
||||||
{
|
|
||||||
struct cansid_state rv = {
|
|
||||||
.state = CANSID_ESC,
|
|
||||||
.style = 0x0F,
|
|
||||||
.next_style = 0x0F
|
|
||||||
};
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned char cansid_convert_color(unsigned char color)
|
|
||||||
{
|
|
||||||
const unsigned char lookup_table[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
|
|
||||||
return lookup_table[(int)color];
|
|
||||||
}
|
|
||||||
|
|
||||||
struct color_char cansid_process(struct cansid_state *state, char x)
|
|
||||||
{
|
|
||||||
struct color_char rv = {
|
|
||||||
.style = state->style,
|
|
||||||
.ascii = '\0'
|
|
||||||
};
|
|
||||||
switch (state->state) {
|
|
||||||
case CANSID_ESC:
|
|
||||||
if (x == ESC)
|
|
||||||
state->state = CANSID_BRACKET;
|
|
||||||
else {
|
|
||||||
rv.ascii = x;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CANSID_BRACKET:
|
|
||||||
if (x == '[')
|
|
||||||
state->state = CANSID_PARSE;
|
|
||||||
else {
|
|
||||||
state->state = CANSID_ESC;
|
|
||||||
rv.ascii = x;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CANSID_PARSE:
|
|
||||||
if (x == '3') {
|
|
||||||
state->state = CANSID_FGCOLOR;
|
|
||||||
} else if (x == '4') {
|
|
||||||
state->state = CANSID_BGCOLOR;
|
|
||||||
} else if (x == '0') {
|
|
||||||
state->state = CANSID_ENDVAL;
|
|
||||||
state->next_style = 0x0F;
|
|
||||||
} else if (x == '1') {
|
|
||||||
state->state = CANSID_ENDVAL;
|
|
||||||
state->next_style |= (1 << 3);
|
|
||||||
} else if (x == '=') {
|
|
||||||
state->state = CANSID_EQUALS;
|
|
||||||
} else {
|
|
||||||
state->state = CANSID_ESC;
|
|
||||||
state->next_style = state->style;
|
|
||||||
rv.ascii = x;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CANSID_BGCOLOR:
|
|
||||||
if (x >= '0' && x <= '7') {
|
|
||||||
state->state = CANSID_ENDVAL;
|
|
||||||
state->next_style &= 0x1F;
|
|
||||||
state->next_style |= cansid_convert_color(x - '0') << 4;
|
|
||||||
} else {
|
|
||||||
state->state = CANSID_ESC;
|
|
||||||
state->next_style = state->style;
|
|
||||||
rv.ascii = x;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CANSID_FGCOLOR:
|
|
||||||
if (x >= '0' && x <= '7') {
|
|
||||||
state->state = CANSID_ENDVAL;
|
|
||||||
state->next_style &= 0xF8;
|
|
||||||
state->next_style |= cansid_convert_color(x - '0');
|
|
||||||
} else {
|
|
||||||
state->state = CANSID_ESC;
|
|
||||||
state->next_style = state->style;
|
|
||||||
rv.ascii = x;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CANSID_EQUALS:
|
|
||||||
if (x == '1') {
|
|
||||||
state->state = CANSID_ENDVAL;
|
|
||||||
state->next_style &= ~(1 << 3);
|
|
||||||
} else {
|
|
||||||
state->state = CANSID_ESC;
|
|
||||||
state->next_style = state->style;
|
|
||||||
rv.ascii = x;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CANSID_ENDVAL:
|
|
||||||
if (x == ';') {
|
|
||||||
state->state = CANSID_PARSE;
|
|
||||||
} else if (x == 'm') {
|
|
||||||
// Finish and apply styles
|
|
||||||
state->state = CANSID_ESC;
|
|
||||||
state->style = state->next_style;
|
|
||||||
} else {
|
|
||||||
state->state = CANSID_ESC;
|
|
||||||
state->next_style = state->style;
|
|
||||||
rv.ascii = x;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
#ifndef CANSID_H
|
|
||||||
#define CANSID_H
|
|
||||||
|
|
||||||
struct cansid_state {
|
|
||||||
enum {
|
|
||||||
CANSID_ESC,
|
|
||||||
CANSID_BRACKET,
|
|
||||||
CANSID_PARSE,
|
|
||||||
CANSID_BGCOLOR,
|
|
||||||
CANSID_FGCOLOR,
|
|
||||||
CANSID_EQUALS,
|
|
||||||
CANSID_ENDVAL,
|
|
||||||
} state;
|
|
||||||
unsigned char style;
|
|
||||||
unsigned char next_style;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct color_char {
|
|
||||||
unsigned char style;
|
|
||||||
unsigned char ascii;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cansid_state cansid_init(void);
|
|
||||||
struct color_char cansid_process(struct cansid_state *state, char x);
|
|
||||||
|
|
||||||
#endif
|
|
@ -3,37 +3,39 @@
|
|||||||
#include "ports.h"
|
#include "ports.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "cansid.h"
|
#include "vtconsole.h"
|
||||||
#define xy_to_indx(x,y) ((x+(y*width))*2)
|
#define xy_to_indx(x,y) ((x+(y*width))*2)
|
||||||
|
static vga_color colors[]={VGA_BLACK,VGA_RED,VGA_GREEN,VGA_BROWN,
|
||||||
|
VGA_BLUE,VGA_PURPLE,VGA_CYAN,VGA_WHITE};
|
||||||
static char* screen;
|
static char* screen;
|
||||||
static int width;
|
static int width;
|
||||||
static int height;
|
static int height;
|
||||||
static int x;
|
|
||||||
static int y;
|
|
||||||
static vga_colors fg_color;
|
|
||||||
static vga_colors bg_color;
|
|
||||||
static char* scroll_buf[0xfa0];
|
|
||||||
|
|
||||||
static struct cansid_state state;
|
static vtconsole_t* console;
|
||||||
|
|
||||||
static void set_char(int x,int y,struct color_char ch) {
|
static void set_char(int x,int y,char ch,char style) {
|
||||||
screen[xy_to_indx(x,y)]=ch.ascii;
|
screen[xy_to_indx(x,y)]=ch;
|
||||||
screen[xy_to_indx(x,y)+1]=ch.style;
|
screen[xy_to_indx(x,y)+1]=style;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vt_set_char(struct vtconsole* vtc, vtcell_t* cell, int x, int y) {
|
||||||
|
vga_color fg_color=colors[cell->attr.fg];
|
||||||
|
vga_color bg_color=colors[cell->attr.bg];
|
||||||
|
char style=(fg_color&0xF)|((bg_color&0xF)<<4);
|
||||||
|
style=style|((cell->attr.bright&0x1)<<7);
|
||||||
|
set_char(x,y,cell->c,style);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_clear() {
|
void vga_clear() {
|
||||||
for (int y=0;y<height;y++) {
|
for (int y=0;y<height;y++) {
|
||||||
for (int x=0;x<width;x++) {
|
for (int x=0;x<width;x++) {
|
||||||
struct color_char ch;
|
set_char(x,y,' ',0);
|
||||||
ch.ascii=' ';
|
|
||||||
ch.style=0;
|
|
||||||
set_char(x,y,ch);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_cursor(int x,int y) {
|
static void set_cursor(struct vtconsole* vtc, vtcursor_t* cur) {
|
||||||
int pos=(x+(y*width));
|
int pos=(cur->x+(cur->y*width));
|
||||||
port_byte_out(0x3D4,0xF);
|
port_byte_out(0x3D4,0xF);
|
||||||
port_byte_out(0x3D5,pos&0xFF);
|
port_byte_out(0x3D5,pos&0xFF);
|
||||||
port_byte_out(0x3D4,0xE);
|
port_byte_out(0x3D4,0xE);
|
||||||
@ -41,56 +43,21 @@ static void set_cursor(int x,int y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void vga_init(text_fb_info framebuffer_info) {
|
void vga_init(text_fb_info framebuffer_info) {
|
||||||
x=0;
|
|
||||||
y=0;
|
|
||||||
fg_color=VGA_WHITE;
|
|
||||||
bg_color=VGA_BLACK;
|
|
||||||
state=cansid_init();
|
|
||||||
screen=framebuffer_info.address;
|
screen=framebuffer_info.address;
|
||||||
width=framebuffer_info.width;
|
width=framebuffer_info.width;
|
||||||
height=framebuffer_info.height;
|
height=framebuffer_info.height;
|
||||||
|
console=vtconsole(width,height,vt_set_char,set_cursor);
|
||||||
port_byte_out(0x3D4,0xA);
|
port_byte_out(0x3D4,0xA);
|
||||||
port_byte_out(0x3D5,(port_byte_in(0x3D5)&0xC0)|14);
|
port_byte_out(0x3D5,(port_byte_in(0x3D5)&0xC0)|14);
|
||||||
port_byte_out(0x3D4,0xB);
|
port_byte_out(0x3D4,0xB);
|
||||||
port_byte_out(0x3D5,(port_byte_in(0x3D5)&0xE0)|15);
|
port_byte_out(0x3D5,(port_byte_in(0x3D5)&0xE0)|15);
|
||||||
set_cursor(0,0);
|
vtcursor_t cur;
|
||||||
|
cur.x=0;
|
||||||
|
cur.y=0;
|
||||||
|
set_cursor(NULL,&cur);
|
||||||
vga_clear();
|
vga_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_write_string(const char* string) {
|
void vga_write_string(const char* string) {
|
||||||
for (size_t i=0;i<strlen(string);i++) {
|
vtconsole_write(console,string,strlen(string));
|
||||||
char c=string[i];
|
|
||||||
if (c=='\n') {
|
|
||||||
x=0;
|
|
||||||
y++;
|
|
||||||
} else {
|
|
||||||
struct color_char ch=cansid_process(&state,c);
|
|
||||||
if (ch.ascii) {
|
|
||||||
set_char(x,y,ch);
|
|
||||||
x++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (x==width) {
|
|
||||||
x=0;
|
|
||||||
y++;
|
|
||||||
}
|
|
||||||
if (y==height) {
|
|
||||||
x=0;
|
|
||||||
y=24;
|
|
||||||
memcpy(scroll_buf,&screen[xy_to_indx(0,1)],xy_to_indx(0,24));
|
|
||||||
vga_clear();
|
|
||||||
memcpy(screen,scroll_buf,xy_to_indx(0,25));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set_cursor(x,y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void vga_backspace() {
|
|
||||||
if (x!=0) {
|
|
||||||
x--;
|
|
||||||
struct color_char ch;
|
|
||||||
ch.ascii=' ';
|
|
||||||
ch.style=0;
|
|
||||||
set_char(x,y,ch);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -10,15 +10,8 @@ typedef enum {
|
|||||||
VGA_PURPLE=5,
|
VGA_PURPLE=5,
|
||||||
VGA_BROWN=6,
|
VGA_BROWN=6,
|
||||||
VGA_GRAY=7,
|
VGA_GRAY=7,
|
||||||
VGA_DARK_GRAY=8,
|
|
||||||
VGA_LIGHT_BLUE=9,
|
|
||||||
VGA_LIGHT_GREEN=10,
|
|
||||||
VGA_LIGHT_CYAN=11,
|
|
||||||
VGA_LIGHT_RED=12,
|
|
||||||
VGA_LIGHT_PURPLE=13,
|
|
||||||
VGA_YELLOW=14,
|
|
||||||
VGA_WHITE=15
|
VGA_WHITE=15
|
||||||
} vga_colors;
|
} vga_color;
|
||||||
|
|
||||||
|
|
||||||
void vga_init();
|
void vga_init();
|
||||||
|
422
vga_drv/vtconsole.c
Executable file
422
vga_drv/vtconsole.c
Executable file
@ -0,0 +1,422 @@
|
|||||||
|
#include "vtconsole.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
|
|
||||||
|
/* --- Constructor/Destructor ----------------------------------------------- */
|
||||||
|
|
||||||
|
vtconsole_t *vtconsole(int width, int height, vtc_paint_handler_t on_paint, vtc_cursor_handler_t on_move)
|
||||||
|
{
|
||||||
|
vtconsole_t *vtc = malloc(sizeof(vtconsole_t));
|
||||||
|
|
||||||
|
vtc->width = width;
|
||||||
|
vtc->height = height;
|
||||||
|
|
||||||
|
vtc->ansiparser = (vtansi_parser_t){VTSTATE_ESC, {{0, 0}}, 0};
|
||||||
|
vtc->attr = VTC_DEFAULT_ATTR;
|
||||||
|
|
||||||
|
vtc->buffer = malloc(width * height * sizeof(vtcell_t));
|
||||||
|
|
||||||
|
vtc->cursor = (vtcursor_t){0, 0};
|
||||||
|
|
||||||
|
vtc->on_paint = on_paint;
|
||||||
|
vtc->on_move = on_move;
|
||||||
|
|
||||||
|
vtconsole_clear(vtc, 0, 0, width, height - 1);
|
||||||
|
|
||||||
|
return vtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vtconsole_delete(vtconsole_t *vtc)
|
||||||
|
{
|
||||||
|
free(vtc->buffer);
|
||||||
|
free(vtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Internal methodes ---------------------------------------------------- */
|
||||||
|
|
||||||
|
void vtconsole_clear(vtconsole_t *vtc, int fromx, int fromy, int tox, int toy)
|
||||||
|
{
|
||||||
|
for (int i = fromx + fromy * vtc->width; i < tox + toy * vtc->width; i++)
|
||||||
|
{
|
||||||
|
vtcell_t *cell = &vtc->buffer[i];
|
||||||
|
|
||||||
|
cell->attr = VTC_DEFAULT_ATTR;
|
||||||
|
cell->c = ' ';
|
||||||
|
|
||||||
|
if (vtc->on_paint)
|
||||||
|
{
|
||||||
|
vtc->on_paint(vtc, cell, i % vtc->width, i / vtc->width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vtconsole_scroll(vtconsole_t *vtc, int lines)
|
||||||
|
{
|
||||||
|
if (lines == 0) return;
|
||||||
|
|
||||||
|
lines = lines > vtc->height ? vtc->height : lines;
|
||||||
|
|
||||||
|
// Scroll the screen by number of $lines.
|
||||||
|
for (int i = 0; i < ((vtc->width * vtc->height) - (vtc->width * lines)); i++)
|
||||||
|
{
|
||||||
|
vtc->buffer[i] = vtc->buffer[i + (vtc->width * lines)];
|
||||||
|
|
||||||
|
if (vtc->on_paint)
|
||||||
|
{
|
||||||
|
vtc->on_paint(vtc, &vtc->buffer[i], i % vtc->width, i / vtc->width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the last $lines.
|
||||||
|
for (int i = ((vtc->width * vtc->height) - (vtc->width * lines)); i < vtc->width * vtc->height; i++)
|
||||||
|
{
|
||||||
|
vtcell_t *cell = &vtc->buffer[i];
|
||||||
|
cell->attr = VTC_DEFAULT_ATTR;
|
||||||
|
cell->c = ' ';
|
||||||
|
|
||||||
|
if (vtc->on_paint)
|
||||||
|
{
|
||||||
|
vtc->on_paint(vtc, &vtc->buffer[i], i % vtc->width, i / vtc->width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the cursor up $lines
|
||||||
|
if (vtc->cursor.y > 0)
|
||||||
|
{
|
||||||
|
vtc->cursor.y -= lines;
|
||||||
|
|
||||||
|
if (vtc->cursor.y < 0) vtc->cursor.y = 0;
|
||||||
|
|
||||||
|
if (vtc->on_move)
|
||||||
|
{
|
||||||
|
vtc->on_move(vtc, &vtc->cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append a new line
|
||||||
|
void vtconsole_newline(vtconsole_t *vtc)
|
||||||
|
{
|
||||||
|
vtc->cursor.x = 0;
|
||||||
|
vtc->cursor.y++;
|
||||||
|
|
||||||
|
if (vtc->cursor.y == vtc->height)
|
||||||
|
{
|
||||||
|
vtconsole_scroll(vtc, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vtc->on_move)
|
||||||
|
{
|
||||||
|
vtc->on_move(vtc, &vtc->cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append character to the console buffer.
|
||||||
|
void vtconsole_append(vtconsole_t *vtc, char c)
|
||||||
|
{
|
||||||
|
if (c == '\n')
|
||||||
|
{
|
||||||
|
vtconsole_newline(vtc);
|
||||||
|
}
|
||||||
|
else if (c == '\r')
|
||||||
|
{
|
||||||
|
vtc->cursor.x = 0;
|
||||||
|
|
||||||
|
if (vtc->on_move)
|
||||||
|
{
|
||||||
|
vtc->on_move(vtc, &vtc->cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == '\t')
|
||||||
|
{
|
||||||
|
int n = 8 - (vtc->cursor.x % 8);
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
vtconsole_append(vtc, ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == '\b')
|
||||||
|
{
|
||||||
|
if (vtc->cursor.x > 0)
|
||||||
|
{
|
||||||
|
vtc->cursor.x--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vtc->cursor.y--;
|
||||||
|
vtc->cursor.x = vtc->width - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vtc->on_move)
|
||||||
|
{
|
||||||
|
vtc->on_move(vtc, &vtc->cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (vtc->cursor.x >= vtc->width)
|
||||||
|
vtconsole_newline(vtc);
|
||||||
|
|
||||||
|
vtcell_t *cell = &vtc->buffer[vtc->cursor.x + vtc->cursor.y * vtc->width];
|
||||||
|
cell->c = c;
|
||||||
|
cell->attr = vtc->attr;
|
||||||
|
|
||||||
|
if (vtc->on_paint)
|
||||||
|
{
|
||||||
|
vtc->on_paint(vtc, cell, vtc->cursor.x, vtc->cursor.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
vtc->cursor.x++;
|
||||||
|
|
||||||
|
if (vtc->on_move)
|
||||||
|
{
|
||||||
|
vtc->on_move(vtc, &vtc->cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Moves the cursor to row n, column m. The values are 1-based,
|
||||||
|
void vtconsole_csi_cup(vtconsole_t *vtc, vtansi_arg_t *stack, int count)
|
||||||
|
{
|
||||||
|
if (count == 1 && stack[0].empty)
|
||||||
|
{
|
||||||
|
vtc->cursor.x = 0;
|
||||||
|
vtc->cursor.y = 0;
|
||||||
|
}
|
||||||
|
else if (count == 2)
|
||||||
|
{
|
||||||
|
if (stack[0].empty)
|
||||||
|
{
|
||||||
|
vtc->cursor.y = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vtc->cursor.y = min(stack[0].value - 1, vtc->height - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stack[1].empty)
|
||||||
|
{
|
||||||
|
vtc->cursor.y = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vtc->cursor.x = min(stack[1].value - 1, vtc->width - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vtc->on_move)
|
||||||
|
{
|
||||||
|
vtc->on_move(vtc, &vtc->cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clears part of the screen.
|
||||||
|
void vtconsole_csi_ed(vtconsole_t *vtc, vtansi_arg_t *stack, int count)
|
||||||
|
{
|
||||||
|
(void)(count);
|
||||||
|
|
||||||
|
vtcursor_t cursor = vtc->cursor;
|
||||||
|
|
||||||
|
if (stack[0].empty)
|
||||||
|
{
|
||||||
|
vtconsole_clear(vtc, cursor.x, cursor.y, vtc->width, vtc->height - 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int attr = stack[0].value;
|
||||||
|
|
||||||
|
if (attr == 0)
|
||||||
|
vtconsole_clear(vtc, cursor.x, cursor.y, vtc->width, vtc->height - 1);
|
||||||
|
else if (attr == 1)
|
||||||
|
vtconsole_clear(vtc, 0, 0, cursor.x, cursor.y);
|
||||||
|
else if (attr == 2)
|
||||||
|
vtconsole_clear(vtc, 0, 0, vtc->width, vtc->height - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erases part of the line.
|
||||||
|
void vtconsole_csi_el(vtconsole_t *vtc, vtansi_arg_t *stack, int count)
|
||||||
|
{
|
||||||
|
(void)(count);
|
||||||
|
|
||||||
|
vtcursor_t cursor = vtc->cursor;
|
||||||
|
|
||||||
|
if (stack[0].empty)
|
||||||
|
{
|
||||||
|
vtconsole_clear(vtc, cursor.x, cursor.y, vtc->width, cursor.y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int attr = stack[0].value;
|
||||||
|
|
||||||
|
if (attr == 0)
|
||||||
|
vtconsole_clear(vtc, cursor.x, cursor.y, vtc->width, cursor.y);
|
||||||
|
else if (attr == 1)
|
||||||
|
vtconsole_clear(vtc, 0, cursor.y, cursor.x, cursor.y);
|
||||||
|
else if (attr == 2)
|
||||||
|
vtconsole_clear(vtc, 0, cursor.y, vtc->width, cursor.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the appearance of the following characters
|
||||||
|
void vtconsole_csi_sgr(vtconsole_t *vtc, vtansi_arg_t *stack, int count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (stack[i].empty || stack[i].value == 0)
|
||||||
|
{
|
||||||
|
vtc->attr = VTC_DEFAULT_ATTR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int attr = stack[i].value;
|
||||||
|
|
||||||
|
if (attr == 1) // Increased intensity
|
||||||
|
{
|
||||||
|
vtc->attr.bright = true;
|
||||||
|
}
|
||||||
|
else if (attr >= 30 && attr <= 37) // Set foreground color
|
||||||
|
{
|
||||||
|
vtc->attr.fg = attr - 30;
|
||||||
|
}
|
||||||
|
else if (attr >= 40 && attr <= 47) // Set background color
|
||||||
|
{
|
||||||
|
vtc->attr.bg = attr - 40;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process ANSI escape sequences and append character to the console buffer.
|
||||||
|
void vtconsole_process(vtconsole_t *vtc, char c)
|
||||||
|
{
|
||||||
|
vtansi_parser_t *parser = &vtc->ansiparser;
|
||||||
|
|
||||||
|
switch (parser->state)
|
||||||
|
{
|
||||||
|
case VTSTATE_ESC:
|
||||||
|
if (c == '\033')
|
||||||
|
{
|
||||||
|
parser->state = VTSTATE_BRACKET;
|
||||||
|
|
||||||
|
parser->index = 0;
|
||||||
|
|
||||||
|
parser->stack[parser->index].value = 0;
|
||||||
|
parser->stack[parser->index].empty = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parser->state = VTSTATE_ESC;
|
||||||
|
vtconsole_append(vtc, c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VTSTATE_BRACKET:
|
||||||
|
if (c == '[')
|
||||||
|
{
|
||||||
|
parser->state = VTSTATE_ATTR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parser->state = VTSTATE_ESC;
|
||||||
|
vtconsole_append(vtc, c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VTSTATE_ATTR:
|
||||||
|
if (isdigit(c))
|
||||||
|
{
|
||||||
|
parser->stack[parser->index].value *= 10;
|
||||||
|
parser->stack[parser->index].value += (c - '0');
|
||||||
|
parser->stack[parser->index].empty = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((parser->index) < VTC_ANSI_PARSER_STACK_SIZE)
|
||||||
|
{
|
||||||
|
parser->index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
parser->stack[parser->index].value = 0;
|
||||||
|
parser->stack[parser->index].empty = true;
|
||||||
|
|
||||||
|
parser->state = VTSTATE_ENDVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser->state == VTSTATE_ENDVAL)
|
||||||
|
{
|
||||||
|
if (c == ';')
|
||||||
|
{
|
||||||
|
parser->state = VTSTATE_ATTR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 'A':
|
||||||
|
/* Cursor up P1 rows */
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
/* Cursor down P1 rows */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'C':
|
||||||
|
/* Cursor right P1 columns */
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
/* Cursor left P1 columns */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'E':
|
||||||
|
/* Cursor to first column of line P1 rows down from current */
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
/* Cursor to first column of line P1 rows up from current */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'G':
|
||||||
|
/* Cursor to column P1 */
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
/* Cursor left P1 columns */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'H':
|
||||||
|
vtconsole_csi_cup(vtc, parser->stack, parser->index);
|
||||||
|
break;
|
||||||
|
case 'J':
|
||||||
|
vtconsole_csi_ed(vtc, parser->stack, parser->index);
|
||||||
|
break;
|
||||||
|
case 'K':
|
||||||
|
vtconsole_csi_el(vtc, parser->stack, parser->index);
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
vtconsole_csi_sgr(vtc, parser->stack, parser->index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
parser->state = VTSTATE_ESC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Methodes ------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void vtconsole_putchar(vtconsole_t *vtc, char c)
|
||||||
|
{
|
||||||
|
vtconsole_process(vtc, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vtconsole_write(vtconsole_t *vtc, const char *buffer, unsigned int size)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
vtconsole_process(vtc, buffer[i]);
|
||||||
|
}
|
||||||
|
}
|
91
vga_drv/vtconsole.h
Executable file
91
vga_drv/vtconsole.h
Executable file
@ -0,0 +1,91 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define VTC_DEFAULT_FOREGROUND VTCOLOR_GREY
|
||||||
|
#define VTC_DEFAULT_BACKGROUND VTCOLOR_BLACK
|
||||||
|
#define VTC_DEFAULT_ATTR (vtattr_t){ false, VTC_DEFAULT_FOREGROUND, VTC_DEFAULT_BACKGROUND }
|
||||||
|
#define VTC_ANSI_PARSER_STACK_SIZE 8
|
||||||
|
|
||||||
|
struct vtconsole;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
VTCOLOR_BLACK,
|
||||||
|
VTCOLOR_RED,
|
||||||
|
VTCOLOR_GREEN,
|
||||||
|
VTCOLOR_YELLOW,
|
||||||
|
VTCOLOR_BLUE,
|
||||||
|
VTCOLOR_MAGENTA,
|
||||||
|
VTCOLOR_CYAN,
|
||||||
|
VTCOLOR_GREY,
|
||||||
|
} vtcolor_t;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
VTSTATE_ESC,
|
||||||
|
VTSTATE_BRACKET,
|
||||||
|
VTSTATE_ATTR,
|
||||||
|
VTSTATE_ENDVAL,
|
||||||
|
} vtansi_parser_state_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
bool empty;
|
||||||
|
} vtansi_arg_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
vtansi_parser_state_t state;
|
||||||
|
vtansi_arg_t stack[VTC_ANSI_PARSER_STACK_SIZE];
|
||||||
|
int index;
|
||||||
|
} vtansi_parser_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
bool bright;
|
||||||
|
vtcolor_t fg;
|
||||||
|
vtcolor_t bg;
|
||||||
|
} vtattr_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
vtattr_t attr;
|
||||||
|
} vtcell_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} vtcursor_t;
|
||||||
|
|
||||||
|
typedef void (*vtc_paint_handler_t)(struct vtconsole* vtc, vtcell_t* cell, int x, int y);
|
||||||
|
typedef void (*vtc_cursor_handler_t)(struct vtconsole* vtc, vtcursor_t* cur);
|
||||||
|
|
||||||
|
typedef struct vtconsole
|
||||||
|
{
|
||||||
|
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
|
||||||
|
vtattr_t attr;
|
||||||
|
vtansi_parser_t ansiparser;
|
||||||
|
|
||||||
|
vtcell_t *buffer;
|
||||||
|
vtcursor_t cursor;
|
||||||
|
|
||||||
|
vtc_paint_handler_t on_paint;
|
||||||
|
vtc_cursor_handler_t on_move;
|
||||||
|
} vtconsole_t;
|
||||||
|
|
||||||
|
vtconsole_t* vtconsole(int width, int height, vtc_paint_handler_t on_paint, vtc_cursor_handler_t on_move);
|
||||||
|
void vtconsole_delete(vtconsole_t *c);
|
||||||
|
|
||||||
|
void vtconsole_clear(vtconsole_t *vtc, int fromx, int fromy, int tox, int toy);
|
||||||
|
void vtconsole_scroll(vtconsole_t *vtc, int lines);
|
||||||
|
void vtconsole_newline(vtconsole_t *vtc);
|
||||||
|
|
||||||
|
void vtconsole_putchar(vtconsole_t *vtc, char c);
|
||||||
|
void vtconsole_write(vtconsole_t *vtc, const char *buffer, unsigned int size);
|
Loading…
x
Reference in New Issue
Block a user