X-Git-Url: http://git.madism.org/?a=blobdiff_plain;f=madtty%2Fmadtty.c;h=e6d9ddefd0d86ab32ae856b33df49c85060ec7b1;hb=7e9bf69df0c4b6cd9a94172e71d7c6a584341f52;hp=d10b91705a2d143cff62aa066d39eb0668a4bfe9;hpb=1f877e6f07a48bc78f0b38d4fba4306d3a4688a2;p=apps%2Fmadtty.git diff --git a/madtty/madtty.c b/madtty/madtty.c index d10b917..e6d9dde 100644 --- a/madtty/madtty.c +++ b/madtty/madtty.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -30,128 +31,93 @@ #include "madtty.h" -#define MAX_CSI_ES_PARAMS 32 -#define ESEQ_BUF_SIZE 128 /* size of escape sequence buffer */ - -/* Terminal private data */ -struct RoteTermPrivate_ { - unsigned escaped : 1; /* whether we are currently reading an - * escape sequence */ - - unsigned graphmode : 1; /* whether terminal is in graphical - * character mode or not */ - - int scrolltop, scrollbottom; /* current scrolling region of terminal */ - int saved_x, saved_y; /* saved cursor position */ - - char esbuf[ESEQ_BUF_SIZE]; /* 0-terminated string. Does NOT include - * the initial escape (\x1B) character. */ - int esbuf_len; /* length of buffer. The following property - * is always kept: esbuf[esbuf_len] == '\0' */ -}; - -static void clamp_cursor_to_bounds(RoteTerm *rt) +static void clamp_cursor_to_bounds(madtty_t *rt) { - if (rt->crow < 0) { - rt->curpos_dirty = true; - rt->crow = 0; + if (rt->curs_row < 0) { + rt->curs_row = 0; } - if (rt->ccol < 0) { - rt->curpos_dirty = true; - rt->ccol = 0; + if (rt->curs_col < 0) { + rt->curs_col = 0; } - if (rt->crow >= rt->rows) { - rt->curpos_dirty = true; - rt->crow = rt->rows - 1; + if (rt->curs_row >= rt->rows) { + rt->curs_row = rt->rows - 1; } - if (rt->ccol >= rt->cols) { - rt->curpos_dirty = true; - rt->ccol = rt->cols - 1; + if (rt->curs_col >= rt->cols) { + rt->curs_col = rt->cols - 1; } } -static void cursor_line_down(RoteTerm *rt) +static void cursor_line_down(madtty_t *rt) { int i; - rt->crow++; - rt->curpos_dirty = true; - if (rt->crow <= rt->pd->scrollbottom) + rt->curs_row++; + if (rt->curs_row <= rt->scrollbottom) return; /* must scroll the scrolling region up by 1 line, and put cursor on * last line of it */ - rt->crow = rt->pd->scrollbottom; + rt->curs_row = rt->scrollbottom; - for (i = rt->pd->scrolltop; i < rt->pd->scrollbottom; i++) { - rt->line_dirty[i] = true; + for (i = rt->scrolltop; i < rt->scrollbottom; i++) { memcpy(rt->cells[i], rt->cells[i+1], sizeof(RoteCell) * rt->cols); } - rt->line_dirty[rt->pd->scrollbottom] = true; - /* clear last row of the scrolling region */ for (i = 0; i < rt->cols; i++) { - rt->cells[rt->pd->scrollbottom][i].s[0] = 0x20; - rt->cells[rt->pd->scrollbottom][i].len = 1; - rt->cells[rt->pd->scrollbottom][i].attr = 0x70; + rt->cells[rt->scrollbottom][i].s[0] = 0x20; + rt->cells[rt->scrollbottom][i].len = 1; + rt->cells[rt->scrollbottom][i].attrs = A_NORMAL; } } -static void cursor_line_up(RoteTerm *rt) +static void cursor_line_up(madtty_t *rt) { int i; - rt->crow--; - rt->curpos_dirty = true; - if (rt->crow >= rt->pd->scrolltop) + rt->curs_row--; + if (rt->curs_row >= rt->scrolltop) return; /* must scroll the scrolling region up by 1 line, and put cursor on * first line of it */ - rt->crow = rt->pd->scrolltop; + rt->curs_row = rt->scrolltop; - for (i = rt->pd->scrollbottom; i > rt->pd->scrolltop; i--) { - rt->line_dirty[i] = true; + for (i = rt->scrollbottom; i > rt->scrolltop; i--) { memcpy(rt->cells[i], rt->cells[i-1], sizeof(RoteCell) * rt->cols); } - rt->line_dirty[rt->pd->scrolltop] = true; - /* clear first row of the scrolling region */ for (i = 0; i < rt->cols; i++) { - rt->cells[rt->pd->scrolltop][i].s[0] = 0x20; - rt->cells[rt->pd->scrolltop][i].len = 1; - rt->cells[rt->pd->scrolltop][i].attr = 0x70; + rt->cells[rt->scrolltop][i].s[0] = 0x20; + rt->cells[rt->scrolltop][i].len = 1; + rt->cells[rt->scrolltop][i].attrs = A_NORMAL; } } -static void put_normal_char(RoteTerm *rt, const char *s, int len) +static void put_normal_char(madtty_t *rt, const char *s, int len) { - if (rt->ccol >= rt->cols) { - rt->ccol = 0; + if (rt->curs_col >= rt->cols) { + rt->curs_col = 0; cursor_line_down(rt); } if (rt->insert) { int i; - for (i = rt->cols - 1; i >= rt->ccol+1; i--) { - rt->cells[rt->crow][i] = rt->cells[rt->crow][i-1]; + for (i = rt->cols - 1; i >= rt->curs_col+1; i--) { + rt->cells[rt->curs_row][i] = rt->cells[rt->curs_row][i-1]; } } - memcpy(rt->cells[rt->crow][rt->ccol].s, s, len); - rt->cells[rt->crow][rt->ccol].len = len; - rt->cells[rt->crow][rt->ccol].attr = rt->curattr; - rt->ccol++; - - rt->line_dirty[rt->crow] = true; - rt->curpos_dirty = true; + memcpy(rt->cells[rt->curs_row][rt->curs_col].s, s, len); + rt->cells[rt->curs_row][rt->curs_col].len = len; + rt->cells[rt->curs_row][rt->curs_col].attrs = rt->curattrs; + rt->curs_col++; } -static void put_graphmode_char(RoteTerm *rt, int c) +static void put_graphmode_char(madtty_t *rt, int c) { char nc; /* do some very pitiful translation to regular ascii chars */ @@ -168,41 +134,39 @@ static void put_graphmode_char(RoteTerm *rt, int c) put_normal_char(rt, &nc, 1); } -static void new_escape_sequence(RoteTerm *rt) +static void new_escape_sequence(madtty_t *rt) { - rt->pd->escaped = true; - rt->pd->esbuf_len = 0; - rt->pd->esbuf[0] = '\0'; + rt->escaped = true; + rt->esbuf_len = 0; + rt->esbuf[0] = '\0'; } -static void cancel_escape_sequence(RoteTerm *rt) +static void cancel_escape_sequence(madtty_t *rt) { - rt->pd->escaped = false; - rt->pd->esbuf_len = 0; - rt->pd->esbuf[0] = '\0'; + rt->escaped = false; + rt->esbuf_len = 0; + rt->esbuf[0] = '\0'; } -static void handle_control_char(RoteTerm *rt, int c) +static void handle_control_char(madtty_t *rt, int c) { switch (c) { case '\r': /* carriage return */ - rt->ccol = 0; + rt->curs_col = 0; break; case '\n': /* line feed */ - rt->ccol = 0; + rt->curs_col = 0; cursor_line_down(rt); - rt->curpos_dirty = true; break; case '\b': /* backspace */ - if (rt->ccol > 0) - rt->ccol--; - rt->curpos_dirty = true; + if (rt->curs_col > 0) + rt->curs_col--; break; case '\t': /* tab */ - rt->ccol = (rt->ccol + 8) & ~7; + rt->curs_col = (rt->curs_col + 8) & ~7; clamp_cursor_to_bounds(rt); break; @@ -211,16 +175,16 @@ static void handle_control_char(RoteTerm *rt, int c) break; case '\x0e': /* enter graphical character mode */ - rt->pd->graphmode = true; + rt->graphmode = true; break; case '\x0f': /* exit graphical character mode */ - rt->pd->graphmode = false; + rt->graphmode = false; break; case '\x9b': /* CSI character. Equivalent to ESC [ */ new_escape_sequence(rt); - rt->pd->esbuf[rt->pd->esbuf_len++] = '['; + rt->esbuf[rt->esbuf_len++] = '['; break; case '\x18': @@ -241,92 +205,14 @@ static bool is_valid_csi_ender(int c) || (c == '@' || c == '`'); } -static void rote_es_interpret_csi(RoteTerm *rt); - -static void try_interpret_escape_seq(RoteTerm *rt) -{ - char firstchar = rt->pd->esbuf[0]; - char lastchar = rt->pd->esbuf[rt->pd->esbuf_len-1]; - - if (!firstchar) - return; /* too early to do anything */ - - /* interpret ESC-M as reverse line-feed */ - if (firstchar == 'M') { - cursor_line_up(rt); - cancel_escape_sequence(rt); - return; - } - - if (firstchar != '[' && firstchar != ']') { - /* unrecognized escape sequence. Let's forget about it. */ - cancel_escape_sequence(rt); - return; - } - - if (firstchar == '[' && is_valid_csi_ender(lastchar)) { - /* we have a csi escape sequence: interpret it */ - rote_es_interpret_csi(rt); - cancel_escape_sequence(rt); - } else if (firstchar == ']' && lastchar == '\a') { - /* we have an xterm escape sequence: interpret it */ - - /* rote_es_interpret_xterm_es(rt); -- TODO!*/ - cancel_escape_sequence(rt); - } - - /* if the escape sequence took up all available space and could - * not yet be parsed, abort it */ - if (rt->pd->esbuf_len + 1 >= ESEQ_BUF_SIZE) - cancel_escape_sequence(rt); -} - -int rote_vt_inject(RoteTerm *rt, const char *data, int len) -{ - int pos; - - for (pos = 0; pos < len; pos++) { - if ((unsigned char)data[pos] <= 31) { - handle_control_char(rt, data[pos]); - continue; - } - - if (rt->pd->escaped && rt->pd->esbuf_len < ESEQ_BUF_SIZE) { - /* append character to ongoing escape sequence */ - rt->pd->esbuf[rt->pd->esbuf_len] = data[pos]; - rt->pd->esbuf[++rt->pd->esbuf_len] = 0; - - try_interpret_escape_seq(rt); - } else - if (rt->pd->graphmode) { - put_graphmode_char(rt, data[pos]); - } else { - static int8_t const lens[5] = { 1, -1, 2, 3, 4 }; - int bsf = __builtin_clz(~((unsigned char)data[pos] << 24)); - - if (pos + lens[bsf] > len) - return pos; - - put_normal_char(rt, data + pos, lens[bsf]); - pos += lens[bsf] - 1; - } - } - - return len; -} - -/****************************************************************************/ -/* CSI things */ -/****************************************************************************/ - /* interprets a 'set attribute' (SGR) CSI escape sequence */ -static void interpret_csi_SGR(RoteTerm *rt, int param[], int pcount) +static void interpret_csi_SGR(madtty_t *rt, int param[], int pcount) { int i; if (pcount == 0) { /* special case: reset attributes */ - rt->curattr = 0x70; + rt->curattrs = A_NORMAL; return; } @@ -353,37 +239,46 @@ static void interpret_csi_SGR(RoteTerm *rt, int param[], int pcount) // 27 Negative image off // 28 Invisible image off - if (param[i] == 0) rt->curattr = 0x70; - else if (param[i] == 1 || param[i] == 2 || param[i] == 4) /* set bold */ - ROTE_ATTR_MOD_BOLD(rt->curattr,1); - else if (param[i] == 5) /* set blink */ - ROTE_ATTR_MOD_BLINK(rt->curattr,1); - else if (param[i] == 7 || param[i] == 27) { /* reverse video */ - int fg = ROTE_ATTR_FG(rt->curattr); - int bg = ROTE_ATTR_BG(rt->curattr); - ROTE_ATTR_MOD_FG(rt->curattr, bg); - ROTE_ATTR_MOD_BG(rt->curattr, fg); + switch (param[i]) { +#define CASE(x, op) case x: op; break + CASE(0, rt->curattrs = A_NORMAL); + CASE(1, rt->curattrs |= A_BOLD); + CASE(4, rt->curattrs |= A_UNDERLINE); + CASE(5, rt->curattrs |= A_BLINK); + CASE(7, rt->curattrs |= A_REVERSE); + CASE(8, rt->curattrs |= A_INVIS); + CASE(22, rt->curattrs &= ~A_BOLD); + CASE(24, rt->curattrs &= ~A_UNDERLINE); + CASE(25, rt->curattrs &= ~A_BLINK); + CASE(27, rt->curattrs &= ~A_REVERSE); + CASE(28, rt->curattrs &= ~A_INVIS); + + case 30 ... 37: + rt->curattrs &= ~070; + rt->curattrs |= (param[i] - 30) << 3; + break; + + case 40 ... 47: + rt->curattrs &= ~007; + rt->curattrs |= (param[i] - 40); + break; + + case 39: + rt->curattrs &= ~070; + break; + + case 49: + rt->curattrs &= ~007; + break; + + default: + break; } - else if (param[i] == 8) rt->curattr = 0x0; /* invisible */ - else if (param[i] == 22 || param[i] == 24) /* bold off */ - ROTE_ATTR_MOD_BOLD(rt->curattr,0); - else if (param[i] == 25) /* blink off */ - ROTE_ATTR_MOD_BLINK(rt->curattr,0); - else if (param[i] == 28) /* invisible off */ - rt->curattr = 0x70; - else if (param[i] >= 30 && param[i] <= 37) /* set fg */ - ROTE_ATTR_MOD_FG(rt->curattr, param[i] - 30); - else if (param[i] >= 40 && param[i] <= 47) /* set bg */ - ROTE_ATTR_MOD_BG(rt->curattr, param[i] - 40); - else if (param[i] == 39) /* reset foreground to default */ - ROTE_ATTR_MOD_FG(rt->curattr, 7); - else if (param[i] == 49) /* reset background to default */ - ROTE_ATTR_MOD_BG(rt->curattr, 0); } } /* interprets an 'erase display' (ED) escape sequence */ -static void interpret_csi_ED(RoteTerm *rt, int param[], int pcount) +static void interpret_csi_ED(madtty_t *rt, int param[], int pcount) { int r, c; int start_row, start_col, end_row, end_col; @@ -398,188 +293,173 @@ static void interpret_csi_ED(RoteTerm *rt, int param[], int pcount) if (pcount && param[0] == 1) { start_row = 0; start_col = 0; - end_row = rt->crow; - end_col = rt->ccol; + end_row = rt->curs_row; + end_col = rt->curs_col; } else { - start_row = rt->crow; - start_col = rt->ccol; + start_row = rt->curs_row; + start_col = rt->curs_col; end_row = rt->rows - 1; end_col = rt->cols - 1; } /* clean range */ for (r = start_row; r <= end_row; r++) { - rt->line_dirty[r] = true; - for (c = (r == start_row ? start_col : 0); c <= (r == end_row ? end_col : rt->cols - 1); c++) { - rt->cells[r][c].s[0] = 0x20; - rt->cells[r][c].len = 1; - rt->cells[r][c].attr = rt->curattr; + rt->cells[r][c].s[0] = 0x20; + rt->cells[r][c].len = 1; + rt->cells[r][c].attrs = rt->curattrs; } } } /* interprets a 'move cursor' (CUP) escape sequence */ -static void interpret_csi_CUP(RoteTerm *rt, int param[], int pcount) +static void interpret_csi_CUP(madtty_t *rt, int param[], int pcount) { if (pcount == 0) { /* special case */ - rt->crow = rt->ccol = 0; + rt->curs_row = rt->curs_col = 0; return; } else if (pcount < 2) { return; /* malformed */ } - rt->crow = param[0] - 1; /* convert from 1-based to 0-based */ - rt->ccol = param[1] - 1; /* convert from 1-based to 0-based */ - - rt->curpos_dirty = true; + rt->curs_row = param[0] - 1; /* convert from 1-based to 0-based */ + rt->curs_col = param[1] - 1; /* convert from 1-based to 0-based */ clamp_cursor_to_bounds(rt); } /* Interpret the 'relative mode' sequences: CUU, CUD, CUF, CUB, CNL, * CPL, CHA, HPR, VPA, VPR, HPA */ -static void interpret_csi_C(RoteTerm *rt, char verb, int param[], int pcount) +static void interpret_csi_C(madtty_t *rt, char verb, int param[], int pcount) { int n = (pcount && param[0] > 0) ? param[0] : 1; switch (verb) { - case 'A': rt->crow -= n; break; - case 'B': case 'e': rt->crow += n; break; - case 'C': case 'a': rt->ccol += n; break; - case 'D': rt->ccol -= n; break; - case 'E': rt->crow += n; rt->ccol = 0; break; - case 'F': rt->crow -= n; rt->ccol = 0; break; - case 'G': case '`': rt->ccol = param[0] - 1; break; - case 'd': rt->crow = param[0] - 1; break; + case 'A': rt->curs_row -= n; break; + case 'B': case 'e': rt->curs_row += n; break; + case 'C': case 'a': rt->curs_col += n; break; + case 'D': rt->curs_col -= n; break; + case 'E': rt->curs_row += n; rt->curs_col = 0; break; + case 'F': rt->curs_row -= n; rt->curs_col = 0; break; + case 'G': case '`': rt->curs_col = param[0] - 1; break; + case 'd': rt->curs_row = param[0] - 1; break; } - rt->curpos_dirty = true; clamp_cursor_to_bounds(rt); } /* Interpret the 'erase line' escape sequence */ -static void interpret_csi_EL(RoteTerm *rt, int param[], int pcount) +static void interpret_csi_EL(madtty_t *rt, int param[], int pcount) { int erase_start, erase_end, i; int cmd = pcount ? param[0] : 0; switch (cmd) { - case 1: erase_start = 0; erase_end = rt->ccol; break; + case 1: erase_start = 0; erase_end = rt->curs_col; break; case 2: erase_start = 0; erase_end = rt->cols - 1; break; - default: erase_start = rt->ccol; erase_end = rt->cols - 1; break; + default: erase_start = rt->curs_col; erase_end = rt->cols - 1; break; } for (i = erase_start; i <= erase_end; i++) { - rt->cells[rt->crow][i].s[0] = 0x20; - rt->cells[rt->crow][i].len = 1; - rt->cells[rt->crow][i].attr = rt->curattr; + rt->cells[rt->curs_row][i].s[0] = 0x20; + rt->cells[rt->curs_row][i].len = 1; + rt->cells[rt->curs_row][i].attrs = rt->curattrs; } - - rt->line_dirty[rt->crow] = true; } /* Interpret the 'insert blanks' sequence (ICH) */ -static void interpret_csi_ICH(RoteTerm *rt, int param[], int pcount) +static void interpret_csi_ICH(madtty_t *rt, int param[], int pcount) { int n = (pcount && param[0] > 0) ? param[0] : 1; int i; - for (i = rt->cols - 1; i >= rt->ccol + n; i--) { - rt->cells[rt->crow][i] = rt->cells[rt->crow][i - n]; + for (i = rt->cols - 1; i >= rt->curs_col + n; i--) { + rt->cells[rt->curs_row][i] = rt->cells[rt->curs_row][i - n]; } - for (i = rt->ccol; i < rt->ccol + n; i++) { - rt->cells[rt->crow][i].s[0] = 0x20; - rt->cells[rt->crow][i].len = 1; - rt->cells[rt->crow][i].attr = rt->curattr; + for (i = rt->curs_col; i < rt->curs_col + n; i++) { + rt->cells[rt->curs_row][i].s[0] = 0x20; + rt->cells[rt->curs_row][i].len = 1; + rt->cells[rt->curs_row][i].attrs = rt->curattrs; } - - rt->line_dirty[rt->crow] = true; } /* Interpret the 'delete chars' sequence (DCH) */ -static void interpret_csi_DCH(RoteTerm *rt, int param[], int pcount) +static void interpret_csi_DCH(madtty_t *rt, int param[], int pcount) { int n = (pcount && param[0] > 0) ? param[0] : 1; int i; - for (i = rt->ccol; i < rt->cols; i++) { + for (i = rt->curs_col; i < rt->cols; i++) { if (i + n < rt->cols) { - rt->cells[rt->crow][i] = rt->cells[rt->crow][i + n]; + rt->cells[rt->curs_row][i] = rt->cells[rt->curs_row][i + n]; } else { - rt->cells[rt->crow][i].s[0] = 0x20; - rt->cells[rt->crow][i].len = 1; - rt->cells[rt->crow][i].attr = rt->curattr; + rt->cells[rt->curs_row][i].s[0] = 0x20; + rt->cells[rt->curs_row][i].len = 1; + rt->cells[rt->curs_row][i].attrs = rt->curattrs; } } - - rt->line_dirty[rt->crow] = true; } /* Interpret an 'insert line' sequence (IL) */ -static void interpret_csi_IL(RoteTerm *rt, int param[], int pcount) +static void interpret_csi_IL(madtty_t *rt, int param[], int pcount) { int n = (pcount && param[0] > 0) ? param[0] : 1; int i, j; - for (i = rt->pd->scrollbottom; i >= rt->crow + n; i--) { + for (i = rt->scrollbottom; i >= rt->curs_row + n; i--) { memcpy(rt->cells[i], rt->cells[i - n], sizeof(RoteCell) * rt->cols); } - for (i = rt->crow; i < rt->crow + n && i <= rt->pd->scrollbottom; i++) { - rt->line_dirty[i] = true; + for (i = rt->curs_row; i < rt->curs_row + n && i <= rt->scrollbottom; i++) { for (j = 0; j < rt->cols; j++) { - rt->cells[i][j].s[0] = 0x20; - rt->cells[i][j].len = 1; - rt->cells[i][j].attr = rt->curattr; + rt->cells[i][j].s[0] = 0x20; + rt->cells[i][j].len = 1; + rt->cells[i][j].attrs = rt->curattrs; } } } /* Interpret a 'delete line' sequence (DL) */ -static void interpret_csi_DL(RoteTerm *rt, int param[], int pcount) +static void interpret_csi_DL(madtty_t *rt, int param[], int pcount) { int n = (pcount && param[0] > 0) ? param[0] : 1; int i, j; - for (i = rt->crow; i <= rt->pd->scrollbottom; i++) { - rt->line_dirty[i] = true; - if (i + n <= rt->pd->scrollbottom) { + for (i = rt->curs_row; i <= rt->scrollbottom; i++) { + if (i + n <= rt->scrollbottom) { memcpy(rt->cells[i], rt->cells[i+n], sizeof(RoteCell) * rt->cols); } else { for (j = 0; j < rt->cols; j++) { - rt->cells[i][j].s[0] = 0x20; - rt->cells[i][j].len = 1; - rt->cells[i][j].attr = rt->curattr; + rt->cells[i][j].s[0] = 0x20; + rt->cells[i][j].len = 1; + rt->cells[i][j].attrs = rt->curattrs; } } } } /* Interpret an 'erase characters' (ECH) sequence */ -static void interpret_csi_ECH(RoteTerm *rt, int param[], int pcount) +static void interpret_csi_ECH(madtty_t *rt, int param[], int pcount) { int n = (pcount && param[0] > 0) ? param[0] : 1; int i; - for (i = rt->ccol; i < rt->ccol + n && i < rt->cols; i++) { - rt->cells[rt->crow][i].s[0] = 0x20; - rt->cells[rt->crow][i].len = 1; - rt->cells[rt->crow][i].attr = rt->curattr; + for (i = rt->curs_col; i < rt->curs_col + n && i < rt->cols; i++) { + rt->cells[rt->curs_row][i].s[0] = 0x20; + rt->cells[rt->curs_row][i].len = 1; + rt->cells[rt->curs_row][i].attrs = rt->curattrs; } - - rt->line_dirty[rt->crow] = true; } /* Interpret a 'set scrolling region' (DECSTBM) sequence */ -static void interpret_csi_DECSTBM(RoteTerm *rt, int param[], int pcount) +static void interpret_csi_DECSTBM(madtty_t *rt, int param[], int pcount) { int newtop, newbottom; @@ -607,37 +487,18 @@ static void interpret_csi_DECSTBM(RoteTerm *rt, int param[], int pcount) /* check for range validity */ if (newtop > newbottom) return; - rt->pd->scrolltop = newtop; - rt->pd->scrollbottom = newbottom; -} - -static void -interpret_csi_SAVECUR(RoteTerm *rt, - int param[] __attribute__((unused)), - int pcount __attribute__((unused))) -{ - rt->pd->saved_x = rt->ccol; - rt->pd->saved_y = rt->crow; -} - -static void -interpret_csi_RESTORECUR(RoteTerm *rt, - int param[] __attribute__((unused)), - int pcount __attribute__((unused))) -{ - rt->ccol = rt->pd->saved_x; - rt->crow = rt->pd->saved_y; - rt->curpos_dirty = true; + rt->scrolltop = newtop; + rt->scrollbottom = newbottom; } -static void rote_es_interpret_csi(RoteTerm *rt) +static void es_interpret_csi(madtty_t *rt) { static int csiparam[MAX_CSI_ES_PARAMS]; int param_count = 0; - const char *p = rt->pd->esbuf + 1; - char verb = rt->pd->esbuf[rt->pd->esbuf_len - 1]; + const char *p = rt->esbuf + 1; + char verb = rt->esbuf[rt->esbuf_len - 1]; - if (!strncmp(rt->pd->esbuf, "[?", 2)) { /* private-mode CSI, ignore */ + if (!strncmp(rt->esbuf, "[?", 2)) { /* private-mode CSI, ignore */ return; } @@ -690,23 +551,98 @@ static void rote_es_interpret_csi(RoteTerm *rt) case 'r': /* set scrolling region */ interpret_csi_DECSTBM(rt, csiparam, param_count); break; case 's': /* save cursor location */ - interpret_csi_SAVECUR(rt, csiparam, param_count); break; + rt->curs_srow = rt->curs_col; + rt->curs_scol = rt->curs_row; + break; case 'u': /* restore cursor location */ - interpret_csi_RESTORECUR(rt, csiparam, param_count); break; + rt->curs_col = rt->curs_srow; + rt->curs_row = rt->curs_scol; + break; default: break; } } -RoteTerm *rote_vt_create(int rows, int cols) +static void try_interpret_escape_seq(madtty_t *rt) { - RoteTerm *rt; + char firstchar = rt->esbuf[0]; + char lastchar = rt->esbuf[rt->esbuf_len-1]; + + if (!firstchar) + return; /* too early to do anything */ + + /* interpret ESC-M as reverse line-feed */ + if (firstchar == 'M') { + cursor_line_up(rt); + cancel_escape_sequence(rt); + return; + } + + if (firstchar != '[' && firstchar != ']') { + /* unrecognized escape sequence. Let's forget about it. */ + cancel_escape_sequence(rt); + return; + } + + if (firstchar == '[' && is_valid_csi_ender(lastchar)) { + es_interpret_csi(rt); + cancel_escape_sequence(rt); + } else if (firstchar == ']' && lastchar == '\a') { + /* we have an xterm escape sequence: interpret it */ + + /* es_interpret_xterm_es(rt); -- TODO!*/ + cancel_escape_sequence(rt); + } + + /* if the escape sequence took up all available space and could + * not yet be parsed, abort it */ + if (rt->esbuf_len + 1 >= ESEQ_BUF_SIZE) + cancel_escape_sequence(rt); +} + +int madtty_inject(madtty_t *rt, const char *data, int len) +{ + int pos; + + for (pos = 0; pos < len; pos++) { + if ((unsigned char)data[pos] <= 31) { + handle_control_char(rt, data[pos]); + continue; + } + + if (rt->escaped && rt->esbuf_len < ESEQ_BUF_SIZE) { + /* append character to ongoing escape sequence */ + rt->esbuf[rt->esbuf_len] = data[pos]; + rt->esbuf[++rt->esbuf_len] = 0; + + try_interpret_escape_seq(rt); + } else + if (rt->graphmode) { + put_graphmode_char(rt, data[pos]); + } else { + static int8_t const lens[5] = { 1, -1, 2, 3, 4 }; + int bsf = __builtin_clz(~((unsigned char)data[pos] << 24)); + + if (pos + lens[bsf] > len) + return pos; + + put_normal_char(rt, data + pos, lens[bsf]); + pos += lens[bsf] - 1; + } + } + + return len; +} + +madtty_t *madtty_create(int rows, int cols) +{ + madtty_t *rt; int i; if (rows <= 0 || cols <= 0) return NULL; - rt = (RoteTerm*)calloc(sizeof(RoteTerm), 1); + rt = (madtty_t*)calloc(sizeof(madtty_t), 1); if (!rt) return NULL; @@ -723,33 +659,25 @@ RoteTerm *rote_vt_create(int rows, int cols) rt->cells[i] = (RoteCell*)calloc(sizeof(RoteCell), rt->cols); } - /* allocate dirtiness array */ - rt->line_dirty = (bool*)calloc(sizeof(bool), rt->rows); - /* initialization of other public fields */ - rt->crow = rt->ccol = 0; - rt->curattr = 0x70; /* white text over black background */ - - /* allocate private data */ - rt->pd = (RoteTermPrivate*)calloc(sizeof(RoteTermPrivate), 1); + rt->curs_row = rt->curs_col = 0; + rt->curattrs = A_NORMAL; /* white text over black background */ rt->pty = -1; /* no pty for now */ /* initial scrolling area is the whole window */ - rt->pd->scrolltop = 0; - rt->pd->scrollbottom = rt->rows - 1; + rt->scrolltop = 0; + rt->scrollbottom = rt->rows - 1; return rt; } -void rote_vt_destroy(RoteTerm *rt) +void madtty_destroy(madtty_t *rt) { int i; if (!rt) return; - free(rt->pd); - free(rt->line_dirty); for (i = 0; i < rt->rows; i++) { free(rt->cells[i]); } @@ -757,30 +685,14 @@ void rote_vt_destroy(RoteTerm *rt) free(rt); } -static void cur_set_attr(WINDOW *win, uint8_t attr) -{ - unsigned cp = ROTE_ATTR_BG(attr) * 8 + 7 - ROTE_ATTR_FG(attr); - wattrset(win, cp ? COLOR_PAIR(cp) : A_NORMAL); - - if (ROTE_ATTR_BOLD(attr)) - wattron(win, A_BOLD); - if (ROTE_ATTR_BLINK(attr)) - wattron(win, A_BLINK); -} - -static unsigned ensure_printable(unsigned ch) -{ - return ch >= 32 ? ch : 32; -} - -void rote_vt_draw(RoteTerm *rt, WINDOW *win, int srow, int scol) +void madtty_draw(madtty_t *rt, WINDOW *win, int srow, int scol) { int i, j; for (i = 0; i < rt->rows; i++) { wmove(win, srow + i, scol); for (j = 0; j < rt->cols; j++) { - cur_set_attr(win, rt->cells[i][j].attr); + wattrset(win, (rt->cells[i][j].attrs & ~077) | COLOR_PAIR(rt->cells[i][j].attrs & 077)); if (rt->cells[i][j].len && rt->cells[i][j].s[0] >= ' ') { waddnstr(win, rt->cells[i][j].s, rt->cells[i][j].len); } else { @@ -789,12 +701,12 @@ void rote_vt_draw(RoteTerm *rt, WINDOW *win, int srow, int scol) } } - wmove(win, srow + rt->crow, scol + rt->ccol); + wmove(win, srow + rt->curs_row, scol + rt->curs_col); } /******************************************************/ -pid_t rote_vt_forkpty(RoteTerm *rt, const char *path, const char *argv[]) +pid_t madtty_forkpty(madtty_t *rt, const char *path, const char *argv[]) { struct winsize ws; pid_t pid; @@ -819,7 +731,7 @@ pid_t rote_vt_forkpty(RoteTerm *rt, const char *path, const char *argv[]) return rt->childpid = pid; } -int rote_vt_read(RoteTerm *rt, char *buf, int buflen) +int madtty_read(madtty_t *rt, char *buf, int buflen) { if (rt->pty < 0) { errno = EINVAL; @@ -829,7 +741,7 @@ int rote_vt_read(RoteTerm *rt, char *buf, int buflen) return read(rt->pty, buf, buflen); } -int rote_vt_write(RoteTerm *rt, const char *data, int len) +int madtty_write(madtty_t *rt, const char *data, int len) { int res; @@ -848,46 +760,38 @@ again: return res; } -static const char *keytable[KEY_MAX+1]; - -static void keytable_init() -{ - memset(keytable, 0, KEY_MAX+1 * sizeof(const char*)); - - keytable['\n'] = "\r"; - keytable[KEY_UP] = "\e[A"; - keytable[KEY_DOWN] = "\e[B"; - keytable[KEY_RIGHT] = "\e[C"; - keytable[KEY_LEFT] = "\e[D"; - keytable[KEY_BACKSPACE] = "\b"; - keytable[KEY_HOME] = "\e[1~"; - keytable[KEY_IC] = "\e[2~"; - keytable[KEY_DC] = "\e[3~"; - keytable[KEY_END] = "\e[4~"; - keytable[KEY_PPAGE] = "\e[5~"; - keytable[KEY_NPAGE] = "\e[6~"; - keytable[KEY_SUSPEND] = "\x1A"; /* Ctrl+Z gets mapped to this */ - keytable[KEY_F(1)] = "\e[[A"; - keytable[KEY_F(2)] = "\e[[B"; - keytable[KEY_F(3)] = "\e[[C"; - keytable[KEY_F(4)] = "\e[[D"; - keytable[KEY_F(5)] = "\e[[E"; - keytable[KEY_F(6)] = "\e[17~"; - keytable[KEY_F(7)] = "\e[18~"; - keytable[KEY_F(8)] = "\e[19~"; - keytable[KEY_F(9)] = "\e[20~"; - keytable[KEY_F(10)] = "\e[21~"; -} +static char const * const keytable[KEY_MAX+1] = { + ['\n'] = "\r", + [KEY_UP] = "\e[A", + [KEY_DOWN] = "\e[B", + [KEY_RIGHT] = "\e[C", + [KEY_LEFT] = "\e[D", + [KEY_BACKSPACE] = "\b", + [KEY_HOME] = "\e[1~", + [KEY_IC] = "\e[2~", + [KEY_DC] = "\e[3~", + [KEY_END] = "\e[4~", + [KEY_PPAGE] = "\e[5~", + [KEY_NPAGE] = "\e[6~", + [KEY_SUSPEND] = "\x1A", /* Ctrl+Z gets mapped to this */ + [KEY_F(1)] = "\e[[A", + [KEY_F(2)] = "\e[[B", + [KEY_F(3)] = "\e[[C", + [KEY_F(4)] = "\e[[D", + [KEY_F(5)] = "\e[[E", + [KEY_F(6)] = "\e[17~", + [KEY_F(7)] = "\e[18~", + [KEY_F(8)] = "\e[19~", + [KEY_F(9)] = "\e[20~", + [KEY_F(10)] = "\e[21~", +}; -void rote_vt_keypress(RoteTerm *rt, int keycode) +void madtty_keypress(madtty_t *rt, int keycode) { char c = (char)keycode; const char *buf; int len; - if (keytable['\n'] == NULL) - keytable_init(); - if (keycode >= 0 && keycode < KEY_MAX && keytable[keycode]) { buf = keytable[keycode]; len = strlen(keytable[keycode]); @@ -897,7 +801,7 @@ void rote_vt_keypress(RoteTerm *rt, int keycode) } while (len > 0) { - int res = rote_vt_write(rt, buf, len); + int res = madtty_write(rt, buf, len); if (res < 0) return; @@ -906,3 +810,16 @@ void rote_vt_keypress(RoteTerm *rt, int keycode) } } +void madtty_initialize(void) +{ + setlocale(LC_ALL, ""); + initscr(); + noecho(); + start_color(); + raw(); + nodelay(stdscr, TRUE); + keypad(stdscr, TRUE); + + for (int i = 0; i < 8 * 8; i++) + init_pair(i, i >> 3, i & 7); +}