diff options
author | June McEnroe <june@causal.agency> | 2019-08-01 16:46:54 -0400 |
---|---|---|
committer | June McEnroe <june@causal.agency> | 2019-08-01 16:46:54 -0400 |
commit | b33d011b79b777c0d51a59b13a4229839a6a77dd (patch) | |
tree | 9b8789e53288fbbb9ddddc3188360a06e381c1ed | |
parent | Factor out SGR handling (diff) | |
download | stream-b33d011b79b777c0d51a59b13a4229839a6a77dd.tar.gz stream-b33d011b79b777c0d51a59b13a4229839a6a77dd.zip |
Implement termSnapshot
-rw-r--r-- | ingest.c | 6 | ||||
-rw-r--r-- | stream.h | 3 | ||||
-rw-r--r-- | term.c | 109 |
3 files changed, 111 insertions, 7 deletions
diff --git a/ingest.c b/ingest.c index 1dfae36..67328a8 100644 --- a/ingest.c +++ b/ingest.c @@ -107,7 +107,11 @@ int main(void) { continue; } - // TODO: Send snapshot. + error = termSnapshot(client); + if (error) { + close(client); + continue; + } maxClient++; assert(client == maxClient); diff --git a/stream.h b/stream.h index d03d30d..56889c2 100644 --- a/stream.h +++ b/stream.h @@ -14,7 +14,10 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <wchar.h> + typedef unsigned uint; void termInit(uint rows, uint cols); void termUpdate(wchar_t ch); +int termSnapshot(int fd); diff --git a/term.c b/term.c index 6fb07da..a79a084 100644 --- a/term.c +++ b/term.c @@ -20,6 +20,7 @@ #include <stdlib.h> #include <string.h> #include <sysexits.h> +#include <unistd.h> #include <wchar.h> #include "stream.h" @@ -36,8 +37,9 @@ enum { struct Style { bool bold, italic, underline, reverse; - uint bg, fg; + int bg, fg; }; +static const struct Style Default = { .bg = -1, .fg = -1 }; struct Cell { struct Style style; @@ -52,7 +54,7 @@ static struct { uint top, bot; } scroll; -static struct Style style = { .bg = -1, .fg = -1 }; +static struct Style style; static struct Cell *cells; static struct Cell *cell(uint y, uint x) { @@ -146,7 +148,7 @@ static char updateESC(wchar_t ch) { } enum { - Default, + Reset, Bold, Italic = 3, Underline, @@ -173,7 +175,7 @@ enum { static void updateSGR(uint ps[], uint n) { for (uint i = 0; i < n; ++i) { switch (ps[i]) { - break; case Default: style = (struct Style) { .bg = -1, .fg = -1 }; + break; case Reset: style = Default; break; case Bold: style.bold = true; break; case Italic: style.italic = true; @@ -235,6 +237,10 @@ enum { DECSTBM = 'r', }; +enum { + Insert = 4, +}; + static char updateCSI(wchar_t ch) { static bool dec; if (ch == DEC) { @@ -300,14 +306,14 @@ static char updateCSI(wchar_t ch) { break; case SM: { if (dec) break; switch (ps[0]) { - break; case 4: insert = true; + break; case Insert: insert = true; break; default: warnx("unhandled SM %u", ps[0]); } } break; case RM: { if (dec) break; switch (ps[0]) { - break; case 4: insert = false; + break; case Insert: insert = false; break; default: warnx("unhandled RM %u", ps[0]); } } @@ -359,6 +365,97 @@ void termInit(uint _rows, uint _cols) { cells = calloc(rows * cols, sizeof(*cells)); if (!cells) err(EX_OSERR, "calloc"); + style = Default; clear(cell(0, 0), cell(rows - 1, cols - 1)); scroll.bot = rows - 1; } + +static int +styleDiff(FILE *file, const struct Style *prev, const struct Style *next) { + if (!memcmp(prev, next, sizeof(*prev))) return 0; + if (!memcmp(next, &Default, sizeof(*next))) { + return fprintf(file, "%c%c%c", ESC, CSI, SGR); + } + uint ps[10]; + uint n = 0; + if (next->bold != prev->bold) { + ps[n++] = (next->bold ? Bold : NotBold); + } + if (next->italic != prev->italic) { + ps[n++] = (next->italic ? Italic : NotItalic); + } + if (next->underline != prev->underline) { + ps[n++] = (next->underline ? Underline : NotUnderline); + } + if (next->reverse != prev->reverse) { + ps[n++] = (next->reverse ? Reverse : NotReverse); + } + if (next->bg != prev->bg) { + if (next->bg == -1) { + ps[n++] = BgDefault; + } else if (next->bg < 8) { + ps[n++] = Bg0 + next->bg; + } else if (next->bg < 16) { + ps[n++] = Bg8 + next->bg - 8; + } else { + ps[n++] = Bg; + ps[n++] = Color256; + ps[n++] = next->bg; + } + } + if (next->fg != prev->fg) { + if (next->fg == -1) { + ps[n++] = FgDefault; + } else if (next->fg < 8) { + ps[n++] = Fg0 + next->fg; + } else if (next->fg < 16) { + ps[n++] = Fg8 + next->fg - 8; + } else { + ps[n++] = Fg; + ps[n++] = Color256; + ps[n++] = next->fg; + } + } + if (0 > fprintf(file, "%c%c%u", ESC, CSI, ps[0])) return -1; + for (uint i = 1; i < n; ++i) { + if (0 > fprintf(file, ";%u", ps[i])) return -1; + } + return fprintf(file, "%c", SGR); +} + +int termSnapshot(int _fd) { + int fd = dup(_fd); + if (fd < 0) return -1; + + FILE *file = fdopen(fd, "w"); + if (!file) return -1; + + struct Style prev = Default; + for (uint y = 0; y < rows; ++y) { + if (y && 0 > fprintf(file, "\r\n")) goto fail; + for (uint x = 0; x < cols; ++x) { + if (!cell(y, x)->ch) continue; + if (0 > styleDiff(file, &prev, &cell(y, x)->style)) goto fail; + if (0 > fprintf(file, "%lc", cell(y, x)->ch)) goto fail; + prev = cell(y, x)->style; + } + } + if (0 > styleDiff(file, &prev, &style)) goto fail; + + int n = fprintf( + file, + "%c%c%d%c" + "%c%c%u;%u%c" + "%c%c%u;%u%c", + ESC, CSI, Insert, (insert ? SM : RM), + ESC, CSI, scroll.top, scroll.bot, DECSTBM, + ESC, CSI, y, x, CUP + ); + if (n < 0) goto fail; + + return fclose(file); + +fail: + fclose(file); + return -1; +} |