aboutsummaryrefslogtreecommitdiff
path: root/src/sysbin/terminal/main.c
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2015-03-14 16:16:53 +0100
committerAlex Auvolat <alex@adnab.me>2015-03-14 16:16:53 +0100
commit57c5eceb846f3109d017b4e6d4cbd7c507c0d098 (patch)
treed4aa0917310a5ad7925736f9dadc07bcb5734383 /src/sysbin/terminal/main.c
parentf574c22f86d90f735107fda199bb5b4982cd9621 (diff)
downloadkogata-57c5eceb846f3109d017b4e6d4cbd7c507c0d098.tar.gz
kogata-57c5eceb846f3109d017b4e6d4cbd7c507c0d098.zip
Begin implement escape sequence handling in terminal.
Diffstat (limited to 'src/sysbin/terminal/main.c')
-rw-r--r--src/sysbin/terminal/main.c209
1 files changed, 164 insertions, 45 deletions
diff --git a/src/sysbin/terminal/main.c b/src/sysbin/terminal/main.c
index 1174305..f0e77e3 100644
--- a/src/sysbin/terminal/main.c
+++ b/src/sysbin/terminal/main.c
@@ -7,6 +7,27 @@
#include <draw.h>
#include <keyboard.h>
+#define NCOLORS 16
+
+const int vga_colors[NCOLORS] = {
+ 0x000000,
+ 0x0000AA,
+ 0x00AA00,
+ 0x00AAAA,
+ 0xAA0000,
+ 0xAA00AA,
+ 0xAA5500,
+ 0xAAAAAA,
+ 0x555555,
+ 0x5555FF,
+ 0x55FF55,
+ 0x55FFFF,
+ 0xFF5555,
+ 0xFF55FF,
+ 0xFFFF55,
+ 0xFFFFFF,
+};
+
typedef char tchar_t;
typedef struct {
@@ -18,7 +39,12 @@ typedef struct {
font_t *font;
int cw, ch; // size of a character
- color_t fg, bg;
+
+ color_t colors[NCOLORS];
+ color_t fg, bg, csr_bg;
+
+ char esc_seq[10]; // current escape sequence
+ int esc_seq_len; // current escape sequence length
keyboard_t *kb;
@@ -32,16 +58,17 @@ typedef struct {
char wr_c_buf;
} term_t;
-void c_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m);
-void c_key_down(gip_handler_t *s, gip_msg_header *p);
-void c_key_up(gip_handler_t *s, gip_msg_header *p);
-void c_unknown_msg(gip_handler_t *s, gip_msg_header *p);
-void c_fd_error(gip_handler_t *s);
+void gip_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m);
+void gip_key_down(gip_handler_t *s, gip_msg_header *p);
+void gip_key_up(gip_handler_t *s, gip_msg_header *p);
+void gip_unknown_msg(gip_handler_t *s, gip_msg_header *p);
+void gip_fd_error(gip_handler_t *s);
+
+void gip_async_initiate(gip_handler_t *s, gip_msg_header *p, void* msgdata, void* hdata);
void term_on_rd_c(mainloop_fd_t *fd);
void term_app_on_error(mainloop_fd_t *fd);
-void c_async_initiate(gip_handler_t *s, gip_msg_header *p, void* msgdata, void* hdata);
gip_handler_callbacks_t term_gip_cb = {
.reset = 0,
@@ -52,13 +79,13 @@ gip_handler_callbacks_t term_gip_cb = {
.disable_features = 0,
.query_mode = 0,
.set_mode = 0,
- .buffer_info = c_buffer_info,
+ .buffer_info = gip_buffer_info,
.mode_info = 0,
.buffer_damage = 0,
- .key_down = c_key_down,
- .key_up = c_key_up,
- .unknown_msg = c_unknown_msg,
- .fd_error = c_fd_error,
+ .key_down = gip_key_down,
+ .key_up = gip_key_up,
+ .unknown_msg = gip_unknown_msg,
+ .fd_error = gip_fd_error,
};
@@ -89,7 +116,7 @@ int main(int argc, char **argv) {
mainloop_expect(&term.app, &term.rd_c_buf, 1, term_on_rd_c);
gip_msg_header reset_msg = { .code = GIPC_RESET, .arg = 0 };
- gip_cmd(h, &reset_msg, 0, c_async_initiate, 0);
+ gip_cmd(h, &reset_msg, 0, gip_async_initiate, 0);
mainloop_run();
@@ -100,7 +127,7 @@ int main(int argc, char **argv) {
void term_draw_c(term_t *t, int l, int c) {
color_t bg = t->bg;
- if (l == t->csrl && c == t->csrc) bg = g_color_rgb(t->fb, 0, 100, 0);
+ if (l == t->csrl && c == t->csrc) bg = t->csr_bg;
char ss[2];
ss[0] = t->scr_chars[l * t->w + c];
@@ -120,6 +147,13 @@ void term_move_cursor(term_t *t, int l, int c) {
term_draw_c(t, l, c);
}
+void term_put_at(term_t *t, int l, int c, tchar_t ch) {
+ if (t->scr_chars[l * t->w + c] == ch) return;
+
+ t->scr_chars[l * t->w + c] = ch;
+ term_draw_c(t, l, c);
+}
+
void term_clear_screen(term_t *t) {
t->csr_visible = true;
@@ -146,32 +180,111 @@ void term_scroll1(term_t *t) {
}
void term_putc(term_t *t, int c) {
- int nl = t->csrl, nc = t->csrc;
- if (c == '\n') {
- nl++; nc = 0;
- } else if (c == '\b') {
- if (nc > 0) {
- nc--;
- } else {
+ if (t->esc_seq_len > 0 || c == '\e') {
+ t->esc_seq[t->esc_seq_len++] = c;
+
+ // parse escape sequence
+ if (t->esc_seq_len >= 2) {
+ if (t->esc_seq[1] == '[') {
+ int n = 0, m = -1;
+ int i = 2;
+ for (; i < t->esc_seq_len && t->esc_seq[i] >= '0' && t->esc_seq[i] <= '9'; i++) {
+ n = (n * 10) + (t->esc_seq[i] - '0');
+ }
+ if (i == t->esc_seq_len) return; // incomplete sequence
+ if (t->esc_seq[i] == ';') {
+ i++;
+ m = 0;
+ for (; i < t->esc_seq_len && t->esc_seq[i] >= '0' && t->esc_seq[i] <= '9'; i++) {
+ m = (m * 10) + (t->esc_seq[i] - 0);
+ }
+ if (i == t->esc_seq_len) return; // incomplete sequence
+ }
+ // TODO implement escape sequence handling
+ if (t->esc_seq[i] == 'A') {
+ // move cursor up
+ } else if (t->esc_seq[i] == 'B') {
+ // move cursor down
+ } else if (t->esc_seq[i] == 'C') {
+ // move cursor forward
+ } else if (t->esc_seq[i] == 'D') {
+ // move cursor back
+ } else if (t->esc_seq[i] == 'E') {
+ // move cursor n lines down to begin of line
+ } else if (t->esc_seq[i] == 'F') {
+ // move cursor n lines up to begin of line
+ } else if (t->esc_seq[i] == 'H' || t->esc_seq[i] == 'f') {
+ // move cursor to position (n, m)
+ } else if (t->esc_seq[i] == 'J' || t->esc_seq[i] == 'K') {
+ // erase data/line
+ } else if (t->esc_seq[i] == 'S') {
+ // scroll up n lines
+ } else if (t->esc_seq[i] == 'T') {
+ // scroll down n lines
+ } else if (t->esc_seq[i] == 'm') {
+ // select graphic rendition (ie color)
+ if (n == 0) {
+ t->fg = t->colors[7];
+ t->bg = t->colors[0];
+ } else if (n >= 30 && n <= 37) {
+ t->fg = t->colors[n - 30];
+ } else if (n == 39) {
+ t->fg = t->colors[7];
+ } else if (n >= 40 && n <= 47) {
+ t->bg = t->colors[n - 40];
+ } else if (n == 49) {
+ t->bg = t->colors[0];
+ }
+ } else if (t->esc_seq[i] == 'n') {
+ // device status report
+ } else if (t->esc_seq[i] == 's') {
+ // save cursor position
+ } else if (t->esc_seq[i] == 'p') {
+ // restore cursor position
+ }
+ }
+ t->esc_seq_len = 0; // sequence finished
+ }
+ } else {
+ int nl = t->csrl, nc = t->csrc;
+ if (c == '\n') {
+ nl++; nc = 0;
+ } else if (c == '\r') {
+ while (nc > 0) {
+ nc--;
+ term_put_at(t, nl, nc, ' ');
+ }
+ nc = 0;
+ } else if (c == '\f') {
+ term_clear_screen(t);
+ return;
+ } else if (c == '\b') {
+ if (nc > 0) {
+ nc--;
+ } else {
+ nl--;
+ nc = t->w - 1;
+ }
+ term_put_at(t, nl, nc, ' ');
+ } else if (c == '\t') {
+ while (nc % 8 != 0) {
+ term_put_at(t, nl, nc, ' ');
+ nc++;
+ }
+ } else if (c >= ' ' && c < 128) {
+ term_put_at(t, nl, nc, c);
+ nc++;
+ }
+ if (nc >= t->w) {
+ nc = 0;
+ nl++;
+ }
+ if (nl >= t->h) {
+ term_scroll1(t);
nl--;
- nc = t->w - 1;
}
- t->scr_chars[nl * t->w + nc] = ' ';
- } else if (c == '\t') {
- while (nc % 4 != 0) nc++;
- } else if (c >= ' ' && c < 128) {
- t->scr_chars[nl * t->w + nc] = c;
- nc++;
- }
- if (nc >= t->w) {
- nc = 0;
- nl++;
+ term_move_cursor(t, nl, nc);
}
- if (nl >= t->h) {
- term_scroll1(t);
- nl--;
- }
- term_move_cursor(t, nl, nc);
}
void term_puts(term_t *t, char* s) {
@@ -183,7 +296,7 @@ void term_puts(term_t *t, char* s) {
// GIP client connection
-void c_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m) {
+void gip_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m) {
dbg_printf("[terminal] Got buffer info msg\n");
term_t *c = (term_t*)s->data;
@@ -215,8 +328,14 @@ void c_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m)
c->fb = g_fb_from_file(c->fd, &m->geom);
if (c->fb != 0) {
- c->bg = g_color_rgb(c->fb, 0, 0, 0);
- c->fg = g_color_rgb(c->fb, 200, 200, 200);
+ for (int i = 0; i < NCOLORS; i++) {
+ c->colors[i] = g_color_rgb(c->fb, (vga_colors[i] >> 16) & 0xFF,
+ (vga_colors[i] >> 8) & 0xFF, vga_colors[i] & 0xFF);
+ }
+ c->bg = c->colors[0];
+ c->fg = c->colors[7];
+ c->csr_bg = c->colors[2];
+
term_clear_screen(c);
mainloop_rm_fd(&c->app);
@@ -228,7 +347,7 @@ void c_buffer_info(gip_handler_t *s, gip_msg_header *p, gip_buffer_info_msg *m)
}
}
-void c_key_down(gip_handler_t *s, gip_msg_header *p) {
+void gip_key_down(gip_handler_t *s, gip_msg_header *p) {
term_t *c = (term_t*)s->data;
key_t k = keyboard_press(c->kb, p->arg);
@@ -244,17 +363,17 @@ void c_key_down(gip_handler_t *s, gip_msg_header *p) {
mainloop_nonblocking_write(&c->app, &c->wr_c_buf, 1, false);
}
-void c_key_up(gip_handler_t *s, gip_msg_header *p) {
+void gip_key_up(gip_handler_t *s, gip_msg_header *p) {
term_t *c = (term_t*)s->data;
keyboard_release(c->kb, p->arg);
}
-void c_unknown_msg(gip_handler_t *s, gip_msg_header *p) {
+void gip_unknown_msg(gip_handler_t *s, gip_msg_header *p) {
// TODO
}
-void c_fd_error(gip_handler_t *s) {
+void gip_fd_error(gip_handler_t *s) {
// TODO
}
@@ -268,7 +387,7 @@ void term_app_on_error(mainloop_fd_t *fd) {
// TODO
}
-void c_async_initiate(gip_handler_t *s, gip_msg_header *p, void* msgdata, void* hdata) {
+void gip_async_initiate(gip_handler_t *s, gip_msg_header *p, void* msgdata, void* hdata) {
term_t *c = (term_t*)s->data;
c->sv_features = p->arg;