diff options
Diffstat (limited to 'sys/cmd/dvtm/driver.c')
-rw-r--r-- | sys/cmd/dvtm/driver.c | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/sys/cmd/dvtm/driver.c b/sys/cmd/dvtm/driver.c new file mode 100644 index 0000000..3e6a518 --- /dev/null +++ b/sys/cmd/dvtm/driver.c @@ -0,0 +1,335 @@ +#include <u.h> +#include <libn.h> +#include <vendor/unibilium.h> + +typedef struct RGB8 RGB8; +typedef struct Pen Pen; +typedef struct Term Term; + +struct ExtraInfo +{ + char *enteralt; + char *exitalt; + + char *entermouse; + char *exitmouse; +}; + +static +struct ExtraInfo vt200 = +{ + .enteralt = "\e[?1049h", + .exitalt = "\e[?1049l", + + .entermouse = "\e[?1049h\e[?1006l", + .exitmouse = "\e[?1002l\e[?1006l", +}; + +struct RGB8 +{ + uint8 r, g, b; +}; + +struct Pen +{ + uint bold : 1; + uint italic : 1; + uint reverse : 1; + uint strike : 1; + uint blink : 1; + + /* colors */ + uint color : 3; + union { + /* 256 color (legacy) */ + struct { + sint fg : 9, bg : 9; /* 0 - 255 or COLOUR_DEFAULT */ + } idx; + /* true color (modern) */ + struct { + RGB8 fg, bg; + } rgb; + }; +}; + +struct Term +{ + /* meta data */ + char *name; + unibi_term *info; + struct { + uint altscreen : 1; + uint cursorvis : 1; + uint mouse : 1; + } mode; + struct { + uint bce : 1; + int colors; + } cap; + + /* input capture */ + // Input *input; + + /* output display */ + int nrow, ncol; + + /* output raw text */ + int fd; + struct { + char *c, b[512]; + } buf; + + struct { + int len; + char *b; + } tmp; + + /* info */ + struct { + /* Positioning */ + char *cup; // cursor_address + char *vpa; // row_address == vertical position absolute + char *hpa; // column_address = horizontal position absolute + + /* Moving */ + char *cuu; char *cuu1; // Cursor Up + char *cud; char *cud1; // Cursor Down + char *cuf; char *cuf1; // Cursor Forward == Right + char *cub; char *cub1; // Cursor Backward == Left + + /* Editing */ + char *ich; char *ich1; // Insert Character + char *dch; char *dch1; // Delete Character + char *il; char *il1; // Insert Line + char *dl; char *dl1; // Delete Line + char *ech; // Erase Character + char *ed2; // Erase Data 2 == Clear screen + char *stbm; // Set Top/Bottom Margins + + /* formatting */ + char *sgr; // Select Graphic Rendition + char *sgr0; // Exit Attribute Mode + char *sgr_i0, *sgr_i1; // SGR italic off/on + char *sgr_fg; // SGR foreground colour + char *sgr_bg; // SGR background colour + + // Mode setting/clearing + char *sm_csr; char *rm_csr; // Set/reset mode: Cursor visible + } esc; +}; + +// ----------------------------------------------------------------------- +// methods + +static +char * +ttmpbuf(Term *t, int len) +{ + if (t->tmp.len >= len) + return t->tmp.b; + + /* TODO: error handling */ + return (t->tmp.b = realloc(t->tmp.b, len)); +} + +void +tflush(Term *t) +{ + if (t->fd != -1) + write(t->fd, t->buf.b, t->buf.c - t->buf.b); + + t->buf.c = t->buf.b; +} + +void +twrite(Term *t, long len, char *s) +{ + int n; + if (!len) + len = strlen(s); + + while (len > 0) { + n = MIN(len, arrend(t->buf.b) - t->buf.c); + memcpy(t->buf.c, s, n); + t->buf.c += n; + len -= n; + tflush(t); + } +} + +static +void +tfmt(Term *t, char *esc, int n, ...) +{ + int i; + long len; + va_list args; + unibi_var_t param[9]; + char buf[64], *c = buf; + + if (!esc) + panicf("no terminfo escape string given"); + + va_start(args, n); + for (i = 0; i < arrlen(param) && i < n; i++) + param[i] = unibi_var_from_num(va_arg(args, int)); + va_end(args); + + len = unibi_run(esc, param, c, sizeof(buf)); + if (len < arrlen(buf)) { + c = ttmpbuf(t, len); + unibi_run(esc, param, c, len); + } + + twrite(t, len, c); +} + +/* absolute move */ +int +tgoto(Term *t, int row, int col) +{ + if (row != -1 && col != -1) + tfmt(t, t->esc.cup, 2, row, col); + else if (row != -1) { + if (!t->esc.vpa) + return 0; + tfmt(t, t->esc.vpa, 1, row); + } else if (col != -1) { + if (col == 0) { + twrite(t, 1, "\r"); + return 1; + } + if (t->esc.hpa) + tfmt(t, t->esc.hpa, 1, col); + else if (t->esc.cuf) { + twrite(t, 1, "\r"); + tfmt(t, t->esc.cuf, 1, col); + } else + return 0; + } else + return 0; /* unreachable */ + + return 1; +} + +/* relative move */ +void +tjump(Term *t, int down, int right) +{ + if (down == 1 && t->esc.cud1) + tfmt(t, t->esc.cud1, 0); + else if (down == -1 && t->esc.cuu1) + tfmt(t, t->esc.cuu1, 0); + else if (down > 0) + tfmt(t, t->esc.cud, 1, down); + else if (down < 0) + tfmt(t, t->esc.cuu, 1, -down); + + if (right == 1 && t->esc.cuf1) + tfmt(t, t->esc.cuf1, 0); + else if (right == -1 && t->esc.cub1) + tfmt (t, t->esc.cub1, 0); + else if (right > 0) + tfmt(t, t->esc.cuf, 1, right); + else if( right < 0) + tfmt(t, t->esc.cub, 1, -right); +} + +void +tdel(Term *t, int num) +{ + char *c, buf[64]; + if (num < 1) + return; + + /* TODO: allow for not moving */ + if (t->cap.bce) { + tfmt(t, t->esc.ech, 1, num); + tjump(t, 0, num); + } else { + c = buf; + memset(c, ' ', arrlen(buf)); + while(num > 64) { + twrite(t, arrlen(buf), c); + num -= arrlen(buf); + } + twrite(t, num, c); + } +} + +void +tclear(Term *t) +{ + tfmt(t, t->esc.ed2, 0); +} + + +// ----------------------------------------------------------------------- +// database lookup + +static +char* +tryinfostr(Term *t, enum unibi_string s) +{ + char *val = (char*)unibi_get_str(t->info, s); + /* TODO: provide fallbacks */ + return val; +} + +static +char* +getinfostr(Term *t, enum unibi_string s) +{ + char *val = tryinfostr(t, s); + if (!val) + panicf("required term info string '%s' missing", unibi_name_str(s)); + + return val; +} + +int +main() +{ + Term t; + + t.name = getenv("TERM"); + t.info = unibi_from_term(t.name); + + t.mode.mouse = 0; + t.mode.cursorvis = 1; + t.mode.altscreen = 0; + + if (!t.info) + panicf("could not identify terminal"); + + t.esc.cup = getinfostr(&t, unibi_cursor_address); + t.esc.vpa = tryinfostr(&t, unibi_row_address); + t.esc.hpa = tryinfostr(&t, unibi_column_address); + t.esc.cuu = getinfostr(&t, unibi_parm_up_cursor); + t.esc.cuu1 = tryinfostr(&t, unibi_cursor_up); + t.esc.cud = getinfostr(&t, unibi_parm_down_cursor); + t.esc.cud1 = tryinfostr(&t, unibi_cursor_down); + t.esc.cuf = getinfostr(&t, unibi_parm_right_cursor); + t.esc.cuf1 = tryinfostr(&t, unibi_cursor_right); + t.esc.cub = getinfostr(&t, unibi_parm_left_cursor); + t.esc.cub1 = tryinfostr(&t, unibi_cursor_left); + t.esc.ich = getinfostr(&t, unibi_parm_ich); + t.esc.ich1 = tryinfostr(&t, unibi_insert_character); + t.esc.dch = getinfostr(&t, unibi_parm_dch); + t.esc.dch1 = tryinfostr(&t, unibi_delete_character); + t.esc.il = getinfostr(&t, unibi_parm_insert_line); + t.esc.il1 = tryinfostr(&t, unibi_insert_line); + t.esc.dl = getinfostr(&t, unibi_parm_delete_line); + t.esc.dl1 = tryinfostr(&t, unibi_delete_line); + t.esc.ech = getinfostr(&t, unibi_erase_chars); + t.esc.ed2 = getinfostr(&t, unibi_clear_screen); + t.esc.stbm = getinfostr(&t, unibi_change_scroll_region); + t.esc.sgr = getinfostr(&t, unibi_set_attributes); + t.esc.sgr0 = getinfostr(&t, unibi_exit_attribute_mode); + t.esc.sgr_i0 = tryinfostr(&t, unibi_exit_italics_mode); + t.esc.sgr_i1 = tryinfostr(&t, unibi_enter_italics_mode); + t.esc.sgr_fg = getinfostr(&t, unibi_set_a_foreground); + t.esc.sgr_bg = getinfostr(&t, unibi_set_a_background); + t.esc.sm_csr = getinfostr(&t, unibi_cursor_normal); + t.esc.rm_csr = getinfostr(&t, unibi_cursor_invisible); +} |