diff options
Diffstat (limited to 'src/libsystemd-terminal/term-screen.c')
-rw-r--r-- | src/libsystemd-terminal/term-screen.c | 4333 |
1 files changed, 0 insertions, 4333 deletions
diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c deleted file mode 100644 index 0e38ff41c6..0000000000 --- a/src/libsystemd-terminal/term-screen.c +++ /dev/null @@ -1,4333 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com> - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -/* - * Terminal Screens - * The term_screen layer implements the terminal-side. It handles all commands - * returned by the seq-parser and applies them to its own pages. - * - * While there are a lot of legacy control-sequences, we only support a small - * subset. There is no reason to implement unused codes like horizontal - * scrolling. - * If you implement new commands, make sure to document them properly. - * - * Standards: - * ECMA-48 - * ANSI X3.64 - * ISO/IEC 6429 - * References: - * http://www.vt100.net/emu/ctrlseq_dec.html - * http://www.vt100.net/docs/vt100-ug/chapter3.html - * http://www.vt100.net/docs/vt510-rm/chapter4 - * http://www.vt100.net/docs/vt510-rm/contents - * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html - * ASCII - * http://en.wikipedia.org/wiki/C0_and_C1_control_codes - * https://en.wikipedia.org/wiki/ANSI_color - */ - -#include <stdbool.h> -#include <stdint.h> -#include <stdlib.h> -#include <xkbcommon/xkbcommon-keysyms.h> -#include "macro.h" -#include "term-internal.h" -#include "util.h" -#include "utf8.h" - -int term_screen_new(term_screen **out, term_screen_write_fn write_fn, void *write_fn_data, term_screen_cmd_fn cmd_fn, void *cmd_fn_data) { - _cleanup_(term_screen_unrefp) term_screen *screen = NULL; - int r; - - assert_return(out, -EINVAL); - - screen = new0(term_screen, 1); - if (!screen) - return -ENOMEM; - - screen->ref = 1; - screen->age = 1; - screen->write_fn = write_fn; - screen->write_fn_data = write_fn_data; - screen->cmd_fn = cmd_fn; - screen->cmd_fn_data = cmd_fn_data; - screen->flags = TERM_FLAG_7BIT_MODE; - screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400; - screen->g0 = &term_unicode_lower; - screen->g1 = &term_unicode_upper; - screen->g2 = &term_unicode_lower; - screen->g3 = &term_unicode_upper; - screen->state.gl = &screen->g0; - screen->state.gr = &screen->g1; - screen->saved = screen->state; - screen->saved_alt = screen->saved; - - r = term_page_new(&screen->page_main); - if (r < 0) - return r; - - r = term_page_new(&screen->page_alt); - if (r < 0) - return r; - - r = term_parser_new(&screen->parser, false); - if (r < 0) - return r; - - r = term_history_new(&screen->history_main); - if (r < 0) - return r; - - screen->page = screen->page_main; - screen->history = screen->history_main; - - *out = screen; - screen = NULL; - return 0; -} - -term_screen *term_screen_ref(term_screen *screen) { - if (!screen) - return NULL; - - assert_return(screen->ref > 0, NULL); - - ++screen->ref; - return screen; -} - -term_screen *term_screen_unref(term_screen *screen) { - if (!screen) - return NULL; - - assert_return(screen->ref > 0, NULL); - - if (--screen->ref) - return NULL; - - free(screen->answerback); - free(screen->tabs); - term_history_free(screen->history_main); - term_page_free(screen->page_alt); - term_page_free(screen->page_main); - term_parser_free(screen->parser); - free(screen); - - return NULL; -} - -/* - * Write-Helpers - * Unfortunately, 7bit/8bit compat mode requires us to send C1 controls encoded - * as 7bit if asked by the application. This is really used in the wild, so we - * cannot fall back to "always 7bit". - * screen_write() is the underlying backend which forwards any writes to the - * users's callback. It's the users responsibility to buffer these and write - * them out once their call to term_screen_feed_*() returns. - * The SEQ_WRITE() and SEQ_WRITE_KEY() macros allow constructing C0/C1 sequences - * directly in the code-base without requiring any intermediate buffer during - * runtime. - */ - -#define C0_CSI "\e[" -#define C1_CSI "\x9b" - -#define SEQ(_screen, _prefix_esc, _c0, _c1, _seq) \ - (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \ - ((_prefix_esc) ? ("\e" _c0 _seq) : (_c0 _seq)) : \ - ((_prefix_esc) ? ("\e" _c1 _seq) : (_c1 _seq))) - -#define SEQ_SIZE(_screen, _prefix_esc, _c0, _c1, _seq) \ - (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \ - ((_prefix_esc) ? sizeof("\e" _c0 _seq) : sizeof(_c0 _seq)) : \ - ((_prefix_esc) ? sizeof("\e" _c1 _seq) : sizeof(_c1 _seq))) - -#define SEQ_WRITE_KEY(_screen, _prefix_esc, _c0, _c1, _seq) \ - screen_write((_screen), \ - SEQ((_screen), (_prefix_esc), \ - _c0, _c1, _seq), \ - SEQ_SIZE((_screen), (_prefix_esc), \ - _c0, _c1, _seq) - 1) - -#define SEQ_WRITE(_screen, _c0, _c1, _seq) \ - SEQ_WRITE_KEY((_screen), false, _c0, _c1, _seq) - -static int screen_write(term_screen *screen, const void *buf, size_t len) { - if (len < 1 || !screen->write_fn) - return 0; - - return screen->write_fn(screen, screen->write_fn_data, buf, len); -} - -/* - * Command Forwarding - * Some commands cannot be handled by the screen-layer directly. Those are - * forwarded to the command-handler of the caller. This is rarely used and can - * safely be set to NULL. - */ - -static int screen_forward(term_screen *screen, unsigned int cmd, const term_seq *seq) { - if (!screen->cmd_fn) - return 0; - - return screen->cmd_fn(screen, screen->cmd_fn_data, cmd, seq); -} - -/* - * Screen Helpers - * These helpers implement common-operations like cursor-handler and more, which - * are used by several command dispatchers. - */ - -static unsigned int screen_clamp_x(term_screen *screen, unsigned int x) { - if (x >= screen->page->width) - return (screen->page->width > 0) ? screen->page->width - 1 : 0; - - return x; -} - -static unsigned int screen_clamp_y(term_screen *screen, unsigned int y) { - if (y >= screen->page->height) - return (screen->page->height > 0) ? screen->page->height - 1 : 0; - - return y; -} - -static bool screen_tab_is_set(term_screen *screen, unsigned int pos) { - if (pos >= screen->page->width) - return false; - - return screen->tabs[pos / 8] & (1 << (pos % 8)); -} - -static inline void screen_age_cursor(term_screen *screen) { - term_cell *cell; - - cell = term_page_get_cell(screen->page, screen->state.cursor_x, screen->state.cursor_y); - if (cell) - cell->age = screen->age; -} - -static void screen_cursor_clear_wrap(term_screen *screen) { - screen->flags &= ~TERM_FLAG_PENDING_WRAP; -} - -static void screen_cursor_set(term_screen *screen, unsigned int x, unsigned int y) { - x = screen_clamp_x(screen, x); - y = screen_clamp_y(screen, y); - - if (x == screen->state.cursor_x && y == screen->state.cursor_y) - return; - - if (!(screen->flags & TERM_FLAG_HIDE_CURSOR)) - screen_age_cursor(screen); - - screen->state.cursor_x = x; - screen->state.cursor_y = y; - - if (!(screen->flags & TERM_FLAG_HIDE_CURSOR)) - screen_age_cursor(screen); -} - -static void screen_cursor_set_rel(term_screen *screen, unsigned int x, unsigned int y) { - if (screen->state.origin_mode) { - x = screen_clamp_x(screen, x); - y = screen_clamp_x(screen, y) + screen->page->scroll_idx; - - if (y >= screen->page->scroll_idx + screen->page->scroll_num) { - y = screen->page->scroll_idx + screen->page->scroll_num; - if (screen->page->scroll_num > 0) - y -= 1; - } - } - - screen_cursor_set(screen, x, y); -} - -static void screen_cursor_left(term_screen *screen, unsigned int num) { - if (num > screen->state.cursor_x) - num = screen->state.cursor_x; - - screen_cursor_set(screen, screen->state.cursor_x - num, screen->state.cursor_y); -} - -static void screen_cursor_left_tab(term_screen *screen, unsigned int num) { - unsigned int i; - - i = screen->state.cursor_x; - while (i > 0 && num > 0) { - if (screen_tab_is_set(screen, --i)) - --num; - } - - screen_cursor_set(screen, i, screen->state.cursor_y); -} - -static void screen_cursor_right(term_screen *screen, unsigned int num) { - if (num > screen->page->width) - num = screen->page->width; - - screen_cursor_set(screen, screen->state.cursor_x + num, screen->state.cursor_y); -} - -static void screen_cursor_right_tab(term_screen *screen, unsigned int num) { - unsigned int i; - - i = screen->state.cursor_x; - while (i + 1 < screen->page->width && num > 0) { - if (screen_tab_is_set(screen, ++i)) - --num; - } - - screen_cursor_set(screen, i, screen->state.cursor_y); -} - -static void screen_cursor_up(term_screen *screen, unsigned int num, bool scroll) { - unsigned int max; - - if (screen->state.cursor_y < screen->page->scroll_idx) { - if (num > screen->state.cursor_y) - num = screen->state.cursor_y; - - screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num); - } else { - max = screen->state.cursor_y - screen->page->scroll_idx; - if (num > max) { - if (num < 1) - return; - - if (!(screen->flags & TERM_FLAG_HIDE_CURSOR)) - screen_age_cursor(screen); - - if (scroll) - term_page_scroll_down(screen->page, num - max, &screen->state.attr, screen->age, NULL); - - screen->state.cursor_y = screen->page->scroll_idx; - - if (!(screen->flags & TERM_FLAG_HIDE_CURSOR)) - screen_age_cursor(screen); - } else { - screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num); - } - } -} - -static void screen_cursor_down(term_screen *screen, unsigned int num, bool scroll) { - unsigned int max; - - if (screen->state.cursor_y >= screen->page->scroll_idx + screen->page->scroll_num) { - if (num > screen->page->height) - num = screen->page->height; - - screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num); - } else { - max = screen->page->scroll_idx + screen->page->scroll_num - 1 - screen->state.cursor_y; - if (num > max) { - if (num < 1) - return; - - if (!(screen->flags & TERM_FLAG_HIDE_CURSOR)) - screen_age_cursor(screen); - - if (scroll) - term_page_scroll_up(screen->page, num - max, &screen->state.attr, screen->age, screen->history); - - screen->state.cursor_y = screen->page->scroll_idx + screen->page->scroll_num - 1; - - if (!(screen->flags & TERM_FLAG_HIDE_CURSOR)) - screen_age_cursor(screen); - } else { - screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y + num); - } - } -} - -static void screen_save_state(term_screen *screen, term_state *where) { - *where = screen->state; -} - -static void screen_restore_state(term_screen *screen, term_state *from) { - screen_cursor_set(screen, from->cursor_x, from->cursor_y); - screen->state = *from; -} - -static void screen_reset_page(term_screen *screen, term_page *page) { - term_page_set_scroll_region(page, 0, page->height); - term_page_erase(page, 0, 0, page->width, page->height, &screen->state.attr, screen->age, false); -} - -static void screen_change_alt(term_screen *screen, bool set) { - if (set) { - screen->page = screen->page_alt; - screen->history = NULL; - } else { - screen->page = screen->page_main; - screen->history = screen->history_main; - } - - screen->page->age = screen->age; -} - -static inline void set_reset(term_screen *screen, unsigned int flag, bool set) { - if (set) - screen->flags |= flag; - else - screen->flags &= ~flag; -} - -static void screen_mode_change_ansi(term_screen *screen, unsigned mode, bool set) { - switch (mode) { - case 20: - /* - * LNM: line-feed/new-line mode - * TODO - */ - set_reset(screen, TERM_FLAG_NEWLINE_MODE, set); - - break; - default: - log_debug("terminal: failed to %s unknown ANSI mode %u", set ? "set" : "unset", mode); - } -} - -static void screen_mode_change_dec(term_screen *screen, unsigned int mode, bool set) { - switch (mode) { - case 1: - /* - * DECCKM: cursor-keys - * TODO - */ - set_reset(screen, TERM_FLAG_CURSOR_KEYS, set); - - break; - case 6: - /* - * DECOM: origin-mode - * TODO - */ - screen->state.origin_mode = set; - - break; - case 7: - /* - * DECAWN: auto-wrap mode - * TODO - */ - screen->state.auto_wrap = set; - - break; - case 25: - /* - * DECTCEM: text-cursor-enable - * TODO - */ - set_reset(screen, TERM_FLAG_HIDE_CURSOR, !set); - screen_age_cursor(screen); - - break; - case 47: - /* - * XTERM-ASB: alternate-screen-buffer - * This enables/disables the alternate screen-buffer. - * It effectively saves the current page content and - * allows you to restore it when changing to the - * original screen-buffer again. - */ - screen_change_alt(screen, set); - - break; - case 1047: - /* - * XTERM-ASBPE: alternate-screen-buffer-post-erase - * This is the same as XTERM-ASB but erases the - * alternate screen-buffer before switching back to the - * original buffer. Use it to discard any data on the - * alternate screen buffer when done. - */ - if (!set) - screen_reset_page(screen, screen->page_alt); - - screen_change_alt(screen, set); - - break; - case 1048: - /* - * XTERM-ASBCS: alternate-screen-buffer-cursor-state - * This has the same effect as DECSC/DECRC, but uses a - * separate state buffer. It is usually used in - * combination with alternate screen buffers to provide - * stacked state storage. - */ - if (set) - screen_save_state(screen, &screen->saved_alt); - else - screen_restore_state(screen, &screen->saved_alt); - - break; - case 1049: - /* - * XTERM-ASBX: alternate-screen-buffer-extended - * This combines XTERM-ASBPE and XTERM-ASBCS somewhat. - * When enabling, state is saved, alternate screen - * buffer is activated and cleared. - * When disabled, alternate screen buffer is cleared, - * then normal screen buffer is enabled and state is - * restored. - */ - if (set) - screen_save_state(screen, &screen->saved_alt); - - screen_reset_page(screen, screen->page_alt); - screen_change_alt(screen, set); - - if (!set) - screen_restore_state(screen, &screen->saved_alt); - - break; - default: - log_debug("terminal: failed to %s unknown DEC mode %u", set ? "set" : "unset", mode); - } -} - -/* map a character according to current GL and GR maps */ -static uint32_t screen_map(term_screen *screen, uint32_t val) { - uint32_t nval = -1U; - - /* 32 and 127 always map to identity. 160 and 255 map to identity iff a - * 96 character set is loaded into GR. Values above 255 always map to - * identity. */ - switch (val) { - case 33 ... 126: - if (screen->state.glt) { - nval = (**screen->state.glt)[val - 32]; - screen->state.glt = NULL; - } else { - nval = (**screen->state.gl)[val - 32]; - } - break; - case 160 ... 255: - if (screen->state.grt) { - nval = (**screen->state.grt)[val - 160]; - screen->state.grt = NULL; - } else { - nval = (**screen->state.gr)[val - 160]; - } - break; - } - - return (nval == -1U) ? val : nval; -} - -/* - * Command Handlers - * This is the unofficial documentation of all the TERM_CMD_* definitions. Each - * handled command has a separate function with an extensive comment on the - * semantics of the command. - * Note that many semantics are unknown and need to be verified. This is mostly - * about error-handling, though. Applications rarely rely on those features. - */ - -static int screen_DA1(term_screen *screen, const term_seq *seq); -static int screen_LF(term_screen *screen, const term_seq *seq); - -static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) { - term_char_t ch = TERM_CHAR_NULL; - - if (screen->state.cursor_x + 1 == screen->page->width - && screen->flags & TERM_FLAG_PENDING_WRAP - && screen->state.auto_wrap) { - screen_cursor_down(screen, 1, true); - screen_cursor_set(screen, 0, screen->state.cursor_y); - } - - screen_cursor_clear_wrap(screen); - - ch = term_char_merge(ch, screen_map(screen, seq->terminator)); - term_page_write(screen->page, screen->state.cursor_x, screen->state.cursor_y, ch, 1, &screen->state.attr, screen->age, false); - - if (screen->state.cursor_x + 1 == screen->page->width) - screen->flags |= TERM_FLAG_PENDING_WRAP; - else - screen_cursor_right(screen, 1); - - return 0; -} - -static int screen_BEL(term_screen *screen, const term_seq *seq) { - /* - * BEL - sound bell tone - * This command should trigger an acoustic bell. Usually, this is - * forwarded directly to the pcspkr. However, bells have become quite - * uncommon and annoying, so we're not implementing them here. Instead, - * it's one of the commands we forward to the caller. - */ - - return screen_forward(screen, TERM_CMD_BEL, seq); -} - -static int screen_BS(term_screen *screen, const term_seq *seq) { - /* - * BS - backspace - * Move cursor one cell to the left. If already at the left margin, - * nothing happens. - */ - - screen_cursor_clear_wrap(screen); - screen_cursor_left(screen, 1); - return 0; -} - -static int screen_CBT(term_screen *screen, const term_seq *seq) { - /* - * CBT - cursor-backward-tabulation - * Move the cursor @args[0] tabs backwards (to the left). The - * current cursor cell, in case it's a tab, is not counted. - * Furthermore, the cursor cannot be moved beyond position 0 and - * it will stop there. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - screen_cursor_clear_wrap(screen); - screen_cursor_left_tab(screen, num); - - return 0; -} - -static int screen_CHA(term_screen *screen, const term_seq *seq) { - /* - * CHA - cursor-horizontal-absolute - * Move the cursor to position @args[0] in the current line. The - * cursor cannot be moved beyond the rightmost cell and will stop - * there. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int pos = 1; - - if (seq->args[0] > 0) - pos = seq->args[0]; - - screen_cursor_clear_wrap(screen); - screen_cursor_set(screen, pos - 1, screen->state.cursor_y); - - return 0; -} - -static int screen_CHT(term_screen *screen, const term_seq *seq) { - /* - * CHT - cursor-horizontal-forward-tabulation - * Move the cursor @args[0] tabs forward (to the right). The - * current cursor cell, in case it's a tab, is not counted. - * Furthermore, the cursor cannot be moved beyond the rightmost cell - * and will stop there. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - screen_cursor_clear_wrap(screen); - screen_cursor_right_tab(screen, num); - - return 0; -} - -static int screen_CNL(term_screen *screen, const term_seq *seq) { - /* - * CNL - cursor-next-line - * Move the cursor @args[0] lines down. - * - * TODO: Does this stop at the bottom or cause a scroll-up? - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - screen_cursor_clear_wrap(screen); - screen_cursor_down(screen, num, false); - - return 0; -} - -static int screen_CPL(term_screen *screen, const term_seq *seq) { - /* - * CPL - cursor-preceding-line - * Move the cursor @args[0] lines up. - * - * TODO: Does this stop at the top or cause a scroll-up? - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - screen_cursor_clear_wrap(screen); - screen_cursor_up(screen, num, false); - - return 0; -} - -static int screen_CR(term_screen *screen, const term_seq *seq) { - /* - * CR - carriage-return - * Move the cursor to the left margin on the current line. - */ - - screen_cursor_clear_wrap(screen); - screen_cursor_set(screen, 0, screen->state.cursor_y); - - return 0; -} - -static int screen_CUB(term_screen *screen, const term_seq *seq) { - /* - * CUB - cursor-backward - * Move the cursor @args[0] positions to the left. The cursor stops - * at the left-most position. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - screen_cursor_clear_wrap(screen); - screen_cursor_left(screen, num); - - return 0; -} - -static int screen_CUD(term_screen *screen, const term_seq *seq) { - /* - * CUD - cursor-down - * Move the cursor @args[0] positions down. The cursor stops at the - * bottom margin. If it was already moved further, it stops at the - * bottom line. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - screen_cursor_clear_wrap(screen); - screen_cursor_down(screen, num, false); - - return 0; -} - -static int screen_CUF(term_screen *screen, const term_seq *seq) { - /* - * CUF -cursor-forward - * Move the cursor @args[0] positions to the right. The cursor stops - * at the right-most position. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - screen_cursor_clear_wrap(screen); - screen_cursor_right(screen, num); - - return 0; -} - -static int screen_CUP(term_screen *screen, const term_seq *seq) { - /* - * CUP - cursor-position - * Moves the cursor to position @args[1] x @args[0]. If either is 0, it - * is treated as 1. The positions are subject to the origin-mode and - * clamped to the addressable with/height. - * - * Defaults: - * args[0]: 1 - * args[1]: 1 - */ - - unsigned int x = 1, y = 1; - - if (seq->args[0] > 0) - y = seq->args[0]; - if (seq->args[1] > 0) - x = seq->args[1]; - - screen_cursor_clear_wrap(screen); - screen_cursor_set_rel(screen, x - 1, y - 1); - - return 0; -} - -static int screen_CUU(term_screen *screen, const term_seq *seq) { - /* - * CUU - cursor-up - * Move the cursor @args[0] positions up. The cursor stops at the - * top margin. If it was already moved further, it stops at the - * top line. - * - * Defaults: - * args[0]: 1 - * - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - screen_cursor_clear_wrap(screen); - screen_cursor_up(screen, num, false); - - return 0; -} - -static int screen_DA1(term_screen *screen, const term_seq *seq) { - /* - * DA1 - primary-device-attributes - * The primary DA asks for basic terminal features. We simply return - * a hard-coded list of features we implement. - * Note that the primary DA asks for supported features, not currently - * enabled features. - * - * The terminal's answer is: - * ^[ ? 64 ; ARGS c - * The first argument, 64, is fixed and denotes a VT420, the last - * DEC-term that extended this number. - * All following arguments denote supported features. Note - * that at most 15 features can be sent (max CSI args). It is safe to - * send more, but clients might not be able to parse them. This is a - * client's problem and we shouldn't care. There is no other way to - * send those feature lists, so we have to extend them beyond 15 in - * those cases. - * - * Known modes: - * 1: 132 column mode - * The 132 column mode is supported by the terminal. - * 2: printer port - * A priner-port is supported and can be addressed via - * control-codes. - * 3: ReGIS graphics - * Support for ReGIS graphics is available. The ReGIS routines - * provide the "remote graphics instruction set" and allow basic - * vector-rendering. - * 4: sixel - * Support of Sixel graphics is available. This provides access - * to the sixel bitmap routines. - * 6: selective erase - * The terminal supports DECSCA and related selective-erase - * functions. This allows to protect specific cells from being - * erased, if specified. - * 7: soft character set (DRCS) - * TODO: ? - * 8: user-defined keys (UDKs) - * TODO: ? - * 9: national-replacement character sets (NRCS) - * National-replacement character-sets are available. - * 12: Yugoslavian (SCS) - * TODO: ? - * 15: technical character set - * The DEC technical-character-set is available. - * 18: windowing capability - * TODO: ? - * 21: horizontal scrolling - * TODO: ? - * 22: ANSII color - * TODO: ? - * 23: Greek - * TODO: ? - * 24: Turkish - * TODO: ? - * 29: ANSI text locator - * TODO: ? - * 42: ISO Latin-2 character set - * TODO: ? - * 44: PCTerm - * TODO: ? - * 45: soft keymap - * TODO: ? - * 46: ASCII emulation - * TODO: ? - */ - - return SEQ_WRITE(screen, C0_CSI, C1_CSI, "?64;1;6;9;15c"); -} - -static int screen_DA2(term_screen *screen, const term_seq *seq) { - /* - * DA2 - secondary-device-attributes - * The secondary DA asks for the terminal-ID, firmware versions and - * other non-primary attributes. All these values are - * informational-only and should not be used by the host to detect - * terminal features. - * - * The terminal's response is: - * ^[ > 61 ; FIRMWARE ; KEYBOARD c - * whereas 65 is fixed for VT525 terminals, the last terminal-line that - * increased this number. FIRMWARE is the firmware - * version encoded as major/minor (20 == 2.0) and KEYBOARD is 0 for STD - * keyboard and 1 for PC keyboards. - * - * We replace the firmware-version with the systemd-version so clients - * can decode it again. - */ - - return SEQ_WRITE(screen, C0_CSI, C1_CSI, ">65;" PACKAGE_VERSION ";1c"); -} - -static int screen_DA3(term_screen *screen, const term_seq *seq) { - /* - * DA3 - tertiary-device-attributes - * The tertiary DA is used to query the terminal-ID. - * - * The terminal's response is: - * ^P ! | XX AA BB CC ^\ - * whereas all four parameters are hexadecimal-encoded pairs. XX - * denotes the manufacturing site, AA BB CC is the terminal's ID. - */ - - /* we do not support tertiary DAs */ - return 0; -} - -static int screen_DC1(term_screen *screen, const term_seq *seq) { - /* - * DC1 - device-control-1 or XON - * This clears any previous XOFF and resumes terminal-transmission. - */ - - /* we do not support XON */ - return 0; -} - -static int screen_DC3(term_screen *screen, const term_seq *seq) { - /* - * DC3 - device-control-3 or XOFF - * Stops terminal transmission. No further characters are sent until - * an XON is received. - */ - - /* we do not support XOFF */ - return 0; -} - -static int screen_DCH(term_screen *screen, const term_seq *seq) { - /* - * DCH - delete-character - * This deletes @argv[0] characters at the current cursor position. As - * characters are deleted, the remaining characters between the cursor - * and right margin move to the left. Character attributes move with the - * characters. The terminal adds blank spaces with no visual character - * attributes at the right margin. DCH has no effect outside the - * scrolling margins. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - screen_cursor_clear_wrap(screen); - term_page_delete_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age); - - return 0; -} - -static int screen_DECALN(term_screen *screen, const term_seq *seq) { - /* - * DECALN - screen-alignment-pattern - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECANM(term_screen *screen, const term_seq *seq) { - /* - * DECANM - ansi-mode - * Set the terminal into VT52 compatibility mode. Control sequences - * overlap with regular sequences so we have to detect them early before - * dispatching them. - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECBI(term_screen *screen, const term_seq *seq) { - /* - * DECBI - back-index - * This control function moves the cursor backward one column. If the - * cursor is at the left margin, then all screen data within the margin - * moves one column to the right. The column that shifted past the right - * margin is lost. - * DECBI adds a new column at the left margin with no visual attributes. - * DECBI does not affect the margins. If the cursor is beyond the - * left-margin at the left border, then the terminal ignores DECBI. - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECCARA(term_screen *screen, const term_seq *seq) { - /* - * DECCARA - change-attributes-in-rectangular-area - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECCRA(term_screen *screen, const term_seq *seq) { - /* - * DECCRA - copy-rectangular-area - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECDC(term_screen *screen, const term_seq *seq) { - /* - * DECDC - delete-column - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECDHL_BH(term_screen *screen, const term_seq *seq) { - /* - * DECDHL_BH - double-width-double-height-line: bottom half - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECDHL_TH(term_screen *screen, const term_seq *seq) { - /* - * DECDHL_TH - double-width-double-height-line: top half - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECDWL(term_screen *screen, const term_seq *seq) { - /* - * DECDWL - double-width-single-height-line - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECEFR(term_screen *screen, const term_seq *seq) { - /* - * DECEFR - enable-filter-rectangle - * Defines the coordinates of a filter rectangle (top, left, bottom, - * right as @args[0] to @args[3]) and activates it. - * Anytime the locator is detected outside of the filter rectangle, an - * outside rectangle event is generated and the rectangle is disabled. - * Filter rectangles are always treated as "one-shot" events. Any - * parameters that are omitted default to the current locator position. - * If all parameters are omitted, any locator motion will be reported. - * DECELR always cancels any prevous rectangle definition. - * - * The locator is usually associated with the mouse-cursor, but based - * on cells instead of pixels. See DECELR how to initialize and enable - * it. DECELR can also enable pixel-mode instead of cell-mode. - * - * TODO: implement - */ - - return 0; -} - -static int screen_DECELF(term_screen *screen, const term_seq *seq) { - /* - * DECELF - enable-local-functions - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECELR(term_screen *screen, const term_seq *seq) { - /* - * DECELR - enable-locator-reporting - * This changes the locator-reporting mode. @args[0] specifies the mode - * to set, 0 disables locator-reporting, 1 enables it continuously, 2 - * enables it for a single report. @args[1] specifies the - * precision-mode. 0 and 2 set the reporting to cell-precision, 1 sets - * pixel-precision. - * - * Defaults: - * args[0]: 0 - * args[1]: 0 - * - * TODO: implement - */ - - return 0; -} - -static int screen_DECERA(term_screen *screen, const term_seq *seq) { - /* - * DECERA - erase-rectangular-area - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECFI(term_screen *screen, const term_seq *seq) { - /* - * DECFI - forward-index - * This control function moves the cursor forward one column. If the - * cursor is at the right margin, then all screen data within the - * margins moves one column to the left. The column shifted past the - * left margin is lost. - * DECFI adds a new column at the right margin, with no visual - * attributes. DECFI does not affect margins. If the cursor is beyond - * the right margin at the border of the page when the terminal - * receives DECFI, then the terminal ignores DECFI. - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECFRA(term_screen *screen, const term_seq *seq) { - /* - * DECFRA - fill-rectangular-area - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECIC(term_screen *screen, const term_seq *seq) { - /* - * DECIC - insert-column - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECID(term_screen *screen, const term_seq *seq) { - /* - * DECID - return-terminal-id - * This is an obsolete form of TERM_CMD_DA1. - */ - - return screen_DA1(screen, seq); -} - -static int screen_DECINVM(term_screen *screen, const term_seq *seq) { - /* - * DECINVM - invoke-macro - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECKBD(term_screen *screen, const term_seq *seq) { - /* - * DECKBD - keyboard-language-selection - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECKPAM(term_screen *screen, const term_seq *seq) { - /* - * DECKPAM - keypad-application-mode - * Enables the keypad-application mode. If enabled, the keypad sends - * special characters instead of the printed characters. This way, - * applications can detect whether a numeric key was pressed on the - * top-row or on the keypad. - * Default is keypad-numeric-mode. - */ - - screen->flags |= TERM_FLAG_KEYPAD_MODE; - - return 0; -} - -static int screen_DECKPNM(term_screen *screen, const term_seq *seq) { - /* - * DECKPNM - keypad-numeric-mode - * This disables the keypad-application-mode (DECKPAM) and returns to - * the keypad-numeric-mode. Keypresses on the keypad generate the same - * sequences as corresponding keypresses on the main keyboard. - * Default is keypad-numeric-mode. - */ - - screen->flags &= ~TERM_FLAG_KEYPAD_MODE; - - return 0; -} - -static int screen_DECLFKC(term_screen *screen, const term_seq *seq) { - /* - * DECLFKC - local-function-key-control - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECLL(term_screen *screen, const term_seq *seq) { - /* - * DECLL - load-leds - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECLTOD(term_screen *screen, const term_seq *seq) { - /* - * DECLTOD - load-time-of-day - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECPCTERM(term_screen *screen, const term_seq *seq) { - /* - * DECPCTERM - pcterm-mode - * This enters/exits the PCTerm mode. Default mode is VT-mode. It can - * also select parameters for scancode/keycode mappings in SCO mode. - * - * Definitely not worth implementing. Lets kill PCTerm/SCO modes! - */ - - return 0; -} - -static int screen_DECPKA(term_screen *screen, const term_seq *seq) { - /* - * DECPKA - program-key-action - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECPKFMR(term_screen *screen, const term_seq *seq) { - /* - * DECPKFMR - program-key-free-memory-report - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECRARA(term_screen *screen, const term_seq *seq) { - /* - * DECRARA - reverse-attributes-in-rectangular-area - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECRC(term_screen *screen, const term_seq *seq) { - /* - * DECRC - restore-cursor - * Restores the terminal to the state saved by the save cursor (DECSC) - * function. This includes more than just the cursor-position. - * - * If nothing was saved by DECSC, then DECRC performs the following - * actions: - * * Moves the cursor to the home position (upper left of screen). - * * Resets origin mode (DECOM). - * * Turns all character attributes off (normal setting). - * * Maps the ASCII character set into GL, and the DEC Supplemental - * Graphic set into GR. - * - * The terminal maintains a separate DECSC buffer for the main display - * and the status line. This feature lets you save a separate operating - * state for the main display and the status line. - */ - - screen_restore_state(screen, &screen->saved); - - return 0; -} - -static int screen_DECREQTPARM(term_screen *screen, const term_seq *seq) { - /* - * DECREQTPARM - request-terminal-parameters - * The sequence DECREPTPARM is sent by the terminal controller to notify - * the host of the status of selected terminal parameters. The status - * sequence may be sent when requested by the host or at the terminal's - * discretion. DECREPTPARM is sent upon receipt of a DECREQTPARM. - * - * If @args[0] is 0, this marks a request and the terminal is allowed - * to send DECREPTPARM messages without request. If it is 1, the same - * applies but the terminal should no longer send DECREPTPARM - * unrequested. - * 2 and 3 mark a report, but 3 is only used if the terminal answers as - * an explicit request with @args[0] == 1. - * - * The other arguments are ignored in requests, but have the following - * meaning in responses: - * args[1]: 1=no-parity-set 4=parity-set-and-odd 5=parity-set-and-even - * args[2]: 1=8bits-per-char 2=7bits-per-char - * args[3]: transmission-speed - * args[4]: receive-speed - * args[5]: 1=bit-rate-multiplier-is-16 - * args[6]: This value communicates the four switch values in block 5 - * of SETUP B, which are only visible to the user when an STP - * option is installed. These bits may be assigned for an STP - * device. The four bits are a decimal-encoded binary number. - * Value between 0-15. - * - * The transmission/receive speeds have mappings for number => bits/s - * which are quite weird. Examples are: 96->3600, 112->9600, 120->19200 - * - * Defaults: - * args[0]: 0 - */ - - if (seq->n_args < 1 || seq->args[0] == 0) { - screen->flags &= ~TERM_FLAG_INHIBIT_TPARM; - return SEQ_WRITE(screen, C0_CSI, C1_CSI, "2;1;1;120;120;1;0x"); - } else if (seq->args[0] == 1) { - screen->flags |= TERM_FLAG_INHIBIT_TPARM; - return SEQ_WRITE(screen, C0_CSI, C1_CSI, "3;1;1;120;120;1;0x"); - } else { - return 0; - } -} - -static int screen_DECRPKT(term_screen *screen, const term_seq *seq) { - /* - * DECRPKT - report-key-type - * Response to DECRQKT, we can safely ignore it as we're the one sending - * it to the host. - */ - - return 0; -} - -static int screen_DECRQCRA(term_screen *screen, const term_seq *seq) { - /* - * DECRQCRA - request-checksum-of-rectangular-area - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECRQDE(term_screen *screen, const term_seq *seq) { - /* - * DECRQDE - request-display-extent - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECRQKT(term_screen *screen, const term_seq *seq) { - /* - * DECRQKT - request-key-type - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECRQLP(term_screen *screen, const term_seq *seq) { - /* - * DECRQLP - request-locator-position - * See DECELR for locator-information. - * - * TODO: document and implement - */ - - return 0; -} - -static int screen_DECRQM_ANSI(term_screen *screen, const term_seq *seq) { - /* - * DECRQM_ANSI - request-mode-ansi - * The host sends this control function to find out if a particular mode - * is set or reset. The terminal responds with a report mode function. - * @args[0] contains the mode to query. - * - * Response is DECRPM with the first argument set to the mode that was - * queried, second argument is 0 if mode is invalid, 1 if mode is set, - * 2 if mode is not set (reset), 3 if mode is permanently set and 4 if - * mode is permanently not set (reset): - * ANSI: ^[ MODE ; VALUE $ y - * DEC: ^[ ? MODE ; VALUE $ y - * - * TODO: implement - */ - - return 0; -} - -static int screen_DECRQM_DEC(term_screen *screen, const term_seq *seq) { - /* - * DECRQM_DEC - request-mode-dec - * Same as DECRQM_ANSI but for DEC modes. - * - * TODO: implement - */ - - return 0; -} - -static int screen_DECRQPKFM(term_screen *screen, const term_seq *seq) { - /* - * DECRQPKFM - request-program-key-free-memory - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECRQPSR(term_screen *screen, const term_seq *seq) { - /* - * DECRQPSR - request-presentation-state-report - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECRQTSR(term_screen *screen, const term_seq *seq) { - /* - * DECRQTSR - request-terminal-state-report - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECRQUPSS(term_screen *screen, const term_seq *seq) { - /* - * DECRQUPSS - request-user-preferred-supplemental-set - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSACE(term_screen *screen, const term_seq *seq) { - /* - * DECSACE - select-attribute-change-extent - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSASD(term_screen *screen, const term_seq *seq) { - /* - * DECSASD - select-active-status-display - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSC(term_screen *screen, const term_seq *seq) { - /* - * DECSC - save-cursor - * Save cursor and terminal state so it can be restored later on. - * Saves the following items in the terminal's memory: - * * Cursor position - * * Character attributes set by the SGR command - * * Character sets (G0, G1, G2, or G3) currently in GL and GR - * * Wrap flag (autowrap or no autowrap) - * * State of origin mode (DECOM) - * * Selective erase attribute - * * Any single shift 2 (SS2) or single shift 3 (SS3) functions sent - */ - - screen_save_state(screen, &screen->saved); - - return 0; -} - -static int screen_DECSCA(term_screen *screen, const term_seq *seq) { - /* - * DECSCA - select-character-protection-attribute - * Defines the characters that come after it as erasable or not erasable - * from the screen. The selective erase control functions (DECSED and - * DECSEL) can only erase characters defined as erasable. - * - * @args[0] specifies the new mode. 0 and 2 mark any following character - * as erasable, 1 marks it as not erasable. - * - * Defaults: - * args[0]: 0 - */ - - unsigned int mode = 0; - - if (seq->args[0] > 0) - mode = seq->args[0]; - - switch (mode) { - case 0: - case 2: - screen->state.attr.protect = 0; - break; - case 1: - screen->state.attr.protect = 1; - break; - } - - return 0; -} - -static int screen_DECSCL(term_screen *screen, const term_seq *seq) { - /* - * DECSCL - select-conformance-level - * Select the terminal's operating level. The factory default is - * level 4 (VT Level 4 mode, 7-bit controls). - * When you change the conformance level, the terminal performs a hard - * reset (RIS). - * - * @args[0] defines the conformance-level, valid values are: - * 61: Level 1 (VT100) - * 62: Level 2 (VT200) - * 63: Level 3 (VT300) - * 64: Level 4 (VT400) - * @args[1] defines the 8bit-mode, valid values are: - * 0: 8-bit controls - * 1: 7-bit controls - * 2: 8-bit controls (same as 0) - * - * If @args[0] is 61, then @args[1] is ignored and 7bit controls are - * enforced. - * - * Defaults: - * args[0]: 64 - * args[1]: 0 - */ - - unsigned int level = 64, bit = 0; - - if (seq->n_args > 0) { - level = seq->args[0]; - if (seq->n_args > 1) - bit = seq->args[1]; - } - - term_screen_hard_reset(screen); - - switch (level) { - case 61: - screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT100; - screen->flags |= TERM_FLAG_7BIT_MODE; - break; - case 62 ... 69: - screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400; - if (bit == 1) - screen->flags |= TERM_FLAG_7BIT_MODE; - else - screen->flags &= ~TERM_FLAG_7BIT_MODE; - break; - } - - return 0; -} - -static int screen_DECSCP(term_screen *screen, const term_seq *seq) { - /* - * DECSCP - select-communication-port - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSCPP(term_screen *screen, const term_seq *seq) { - /* - * DECSCPP - select-columns-per-page - * Select columns per page. The number of rows is unaffected by this. - * @args[0] selectes the number of columns (width), DEC only defines 80 - * and 132, but we allow any integer here. 0 is equivalent to 80. - * Page content is *not* cleared and the cursor is left untouched. - * However, if the page is reduced in width and the cursor would be - * outside the visible region, it's set to the right border. Newly added - * cells are cleared. No data is retained outside the visible region. - * - * Defaults: - * args[0]: 0 - * - * TODO: implement - */ - - return 0; -} - -static int screen_DECSCS(term_screen *screen, const term_seq *seq) { - /* - * DECSCS - select-communication-speed - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSCUSR(term_screen *screen, const term_seq *seq) { - /* - * DECSCUSR - set-cursor-style - * This changes the style of the cursor. @args[0] can be one of: - * 0, 1: blinking block - * 2: steady block - * 3: blinking underline - * 4: steady underline - * Changing this setting does _not_ affect the cursor visibility itself. - * Use DECTCEM for that. - * - * Defaults: - * args[0]: 0 - * - * TODO: implement - */ - - return 0; -} - -static int screen_DECSDDT(term_screen *screen, const term_seq *seq) { - /* - * DECSDDT - select-disconnect-delay-time - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSDPT(term_screen *screen, const term_seq *seq) { - /* - * DECSDPT - select-digital-printed-data-type - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSED(term_screen *screen, const term_seq *seq) { - /* - * DECSED - selective-erase-in-display - * This control function erases some or all of the erasable characters - * in the display. DECSED can only erase characters defined as erasable - * by the DECSCA control function. DECSED works inside or outside the - * scrolling margins. - * - * @args[0] defines which regions are erased. If it is 0, all cells from - * the cursor (inclusive) till the end of the display are erase. If it - * is 1, all cells from the start of the display till the cursor - * (inclusive) are erased. If it is 2, all cells are erased. - * - * Defaults: - * args[0]: 0 - */ - - unsigned int mode = 0; - - if (seq->args[0] > 0) - mode = seq->args[0]; - - switch (mode) { - case 0: - term_page_erase(screen->page, - screen->state.cursor_x, screen->state.cursor_y, - screen->page->width, screen->page->height, - &screen->state.attr, screen->age, true); - break; - case 1: - term_page_erase(screen->page, - 0, 0, - screen->state.cursor_x, screen->state.cursor_y, - &screen->state.attr, screen->age, true); - break; - case 2: - term_page_erase(screen->page, - 0, 0, - screen->page->width, screen->page->height, - &screen->state.attr, screen->age, true); - break; - } - - return 0; -} - -static int screen_DECSEL(term_screen *screen, const term_seq *seq) { - /* - * DECSEL - selective-erase-in-line - * This control function erases some or all of the erasable characters - * in a single line of text. DECSEL erases only those characters defined - * as erasable by the DECSCA control function. DECSEL works inside or - * outside the scrolling margins. - * - * @args[0] defines the region to be erased. If it is 0, all cells from - * the cursor (inclusive) till the end of the line are erase. If it is - * 1, all cells from the start of the line till the cursor (inclusive) - * are erased. If it is 2, the whole line of the cursor is erased. - * - * Defaults: - * args[0]: 0 - */ - - unsigned int mode = 0; - - if (seq->args[0] > 0) - mode = seq->args[0]; - - switch (mode) { - case 0: - term_page_erase(screen->page, - screen->state.cursor_x, screen->state.cursor_y, - screen->page->width, screen->state.cursor_y, - &screen->state.attr, screen->age, true); - break; - case 1: - term_page_erase(screen->page, - 0, screen->state.cursor_y, - screen->state.cursor_x, screen->state.cursor_y, - &screen->state.attr, screen->age, true); - break; - case 2: - term_page_erase(screen->page, - 0, screen->state.cursor_y, - screen->page->width, screen->state.cursor_y, - &screen->state.attr, screen->age, true); - break; - } - - return 0; -} - -static int screen_DECSERA(term_screen *screen, const term_seq *seq) { - /* - * DECSERA - selective-erase-rectangular-area - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSFC(term_screen *screen, const term_seq *seq) { - /* - * DECSFC - select-flow-control - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSKCV(term_screen *screen, const term_seq *seq) { - /* - * DECSKCV - set-key-click-volume - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSLCK(term_screen *screen, const term_seq *seq) { - /* - * DECSLCK - set-lock-key-style - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSLE(term_screen *screen, const term_seq *seq) { - /* - * DECSLE - select-locator-events - * - * TODO: implement - */ - - return 0; -} - -static int screen_DECSLPP(term_screen *screen, const term_seq *seq) { - /* - * DECSLPP - set-lines-per-page - * Set the number of lines used for the page. @args[0] specifies the - * number of lines to be used. DEC only allows a limited number of - * choices, however, we allow all integers. 0 is equivalent to 24. - * - * Defaults: - * args[0]: 0 - * - * TODO: implement - */ - - return 0; -} - -static int screen_DECSLRM_OR_SC(term_screen *screen, const term_seq *seq) { - /* - * DECSLRM_OR_SC - set-left-and-right-margins or save-cursor - * - * TODO: Detect save-cursor and run it. DECSLRM is not worth - * implementing. - */ - - return 0; -} - -static int screen_DECSMBV(term_screen *screen, const term_seq *seq) { - /* - * DECSMBV - set-margin-bell-volume - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSMKR(term_screen *screen, const term_seq *seq) { - /* - * DECSMKR - select-modifier-key-reporting - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSNLS(term_screen *screen, const term_seq *seq) { - /* - * DECSNLS - set-lines-per-screen - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSPP(term_screen *screen, const term_seq *seq) { - /* - * DECSPP - set-port-parameter - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSPPCS(term_screen *screen, const term_seq *seq) { - /* - * DECSPPCS - select-pro-printer-character-set - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSPRTT(term_screen *screen, const term_seq *seq) { - /* - * DECSPRTT - select-printer-type - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSR(term_screen *screen, const term_seq *seq) { - /* - * DECSR - secure-reset - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSRFR(term_screen *screen, const term_seq *seq) { - /* - * DECSRFR - select-refresh-rate - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSSCLS(term_screen *screen, const term_seq *seq) { - /* - * DECSSCLS - set-scroll-speed - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSSDT(term_screen *screen, const term_seq *seq) { - /* - * DECSSDT - select-status-display-line-type - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSSL(term_screen *screen, const term_seq *seq) { - /* - * DECSSL - select-setup-language - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECST8C(term_screen *screen, const term_seq *seq) { - /* - * DECST8C - set-tab-at-every-8-columns - * Clear the tab-ruler and reset it to a tab at every 8th column, - * starting at 9 (though, setting a tab at 1 is fine as it has no - * effect). - */ - - unsigned int i; - - for (i = 0; i < screen->page->width; i += 8) - screen->tabs[i / 8] = 0x1; - - return 0; -} - -static int screen_DECSTBM(term_screen *screen, const term_seq *seq) { - /* - * DECSTBM - set-top-and-bottom-margins - * This control function sets the top and bottom margins for the current - * page. You cannot perform scrolling outside the margins. - * - * @args[0] defines the top margin, @args[1] defines the bottom margin. - * The bottom margin must be lower than the top-margin. - * - * This call resets the cursor position to 0/0 of the page. - * - * Defaults: - * args[0]: 1 - * args[1]: last page-line - */ - - unsigned int top, bottom; - - top = 1; - bottom = screen->page->height; - - if (seq->args[0] > 0) - top = seq->args[0]; - if (seq->args[1] > 0) - bottom = seq->args[1]; - - if (top > screen->page->height) - top = screen->page->height; - if (bottom > screen->page->height) - bottom = screen->page->height; - - if (top >= bottom || top > screen->page->height || bottom > screen->page->height) { - top = 1; - bottom = screen->page->height; - } - - term_page_set_scroll_region(screen->page, top - 1, bottom - top + 1); - screen_cursor_clear_wrap(screen); - screen_cursor_set(screen, 0, 0); - - return 0; -} - -static int screen_DECSTR(term_screen *screen, const term_seq *seq) { - /* - * DECSTR - soft-terminal-reset - * Perform a soft reset to the default values. - */ - - term_screen_soft_reset(screen); - - return 0; -} - -static int screen_DECSTRL(term_screen *screen, const term_seq *seq) { - /* - * DECSTRL - set-transmit-rate-limit - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSWBV(term_screen *screen, const term_seq *seq) { - /* - * DECSWBV - set-warning-bell-volume - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECSWL(term_screen *screen, const term_seq *seq) { - /* - * DECSWL - single-width-single-height-line - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECTID(term_screen *screen, const term_seq *seq) { - /* - * DECTID - select-terminal-id - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECTME(term_screen *screen, const term_seq *seq) { - /* - * DECTME - terminal-mode-emulation - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DECTST(term_screen *screen, const term_seq *seq) { - /* - * DECTST - invoke-confidence-test - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_DL(term_screen *screen, const term_seq *seq) { - /* - * DL - delete-line - * This control function deletes one or more lines in the scrolling - * region, starting with the line that has the cursor. @args[0] defines - * the number of lines to delete. 0 is treated the same as 1. - * As lines are deleted, lines below the cursor and in the scrolling - * region move up. The terminal adds blank lines with no visual - * character attributes at the bottom of the scrolling region. If it is - * greater than the number of lines remaining on the page, DL deletes - * only the remaining lines. DL has no effect outside the scrolling - * margins. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - term_page_delete_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age); - - return 0; -} - -static int screen_DSR_ANSI(term_screen *screen, const term_seq *seq) { - /* - * DSR_ANSI - device-status-report-ansi - * - * TODO: implement - */ - - return 0; -} - -static int screen_DSR_DEC(term_screen *screen, const term_seq *seq) { - /* - * DSR_DEC - device-status-report-dec - * - * TODO: implement - */ - - return 0; -} - -static int screen_ECH(term_screen *screen, const term_seq *seq) { - /* - * ECH - erase-character - * This control function erases one or more characters, from the cursor - * position to the right. ECH clears character attributes from erased - * character positions. ECH works inside or outside the scrolling - * margins. - * @args[0] defines the number of characters to erase. 0 is treated the - * same as 1. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - term_page_erase(screen->page, - screen->state.cursor_x, screen->state.cursor_y, - screen->state.cursor_x + num, screen->state.cursor_y, - &screen->state.attr, screen->age, false); - - return 0; -} - -static int screen_ED(term_screen *screen, const term_seq *seq) { - /* - * ED - erase-in-display - * This control function erases characters from part or all of the - * display. When you erase complete lines, they become single-height, - * single-width lines, with all visual character attributes cleared. ED - * works inside or outside the scrolling margins. - * - * @args[0] defines the region to erase. 0 means from cursor (inclusive) - * till the end of the screen. 1 means from the start of the screen till - * the cursor (inclusive) and 2 means the whole screen. - * - * Defaults: - * args[0]: 0 - */ - - unsigned int mode = 0; - - if (seq->args[0] > 0) - mode = seq->args[0]; - - switch (mode) { - case 0: - term_page_erase(screen->page, - screen->state.cursor_x, screen->state.cursor_y, - screen->page->width, screen->page->height, - &screen->state.attr, screen->age, false); - break; - case 1: - term_page_erase(screen->page, - 0, 0, - screen->state.cursor_x, screen->state.cursor_y, - &screen->state.attr, screen->age, false); - break; - case 2: - term_page_erase(screen->page, - 0, 0, - screen->page->width, screen->page->height, - &screen->state.attr, screen->age, false); - break; - } - - return 0; -} - -static int screen_EL(term_screen *screen, const term_seq *seq) { - /* - * EL - erase-in-line - * This control function erases characters on the line that has the - * cursor. EL clears all character attributes from erased character - * positions. EL works inside or outside the scrolling margins. - * - * @args[0] defines the region to erase. 0 means from cursor (inclusive) - * till the end of the line. 1 means from the start of the line till the - * cursor (inclusive) and 2 means the whole line. - * - * Defaults: - * args[0]: 0 - */ - - unsigned int mode = 0; - - if (seq->args[0] > 0) - mode = seq->args[0]; - - switch (mode) { - case 0: - term_page_erase(screen->page, - screen->state.cursor_x, screen->state.cursor_y, - screen->page->width, screen->state.cursor_y, - &screen->state.attr, screen->age, false); - break; - case 1: - term_page_erase(screen->page, - 0, screen->state.cursor_y, - screen->state.cursor_x, screen->state.cursor_y, - &screen->state.attr, screen->age, false); - break; - case 2: - term_page_erase(screen->page, - 0, screen->state.cursor_y, - screen->page->width, screen->state.cursor_y, - &screen->state.attr, screen->age, false); - break; - } - - return 0; -} - -static int screen_ENQ(term_screen *screen, const term_seq *seq) { - /* - * ENQ - enquiry - * Transmit the answerback-string. If none is set, do nothing. - */ - - if (screen->answerback) - return screen_write(screen, screen->answerback, strlen(screen->answerback)); - - return 0; -} - -static int screen_EPA(term_screen *screen, const term_seq *seq) { - /* - * EPA - end-of-guarded-area - * - * TODO: What is this? - */ - - return 0; -} - -static int screen_FF(term_screen *screen, const term_seq *seq) { - /* - * FF - form-feed - * This causes the cursor to jump to the next line. It is treated the - * same as LF. - */ - - return screen_LF(screen, seq); -} - -static int screen_HPA(term_screen *screen, const term_seq *seq) { - /* - * HPA - horizontal-position-absolute - * HPA causes the active position to be moved to the n-th horizontal - * position of the active line. If an attempt is made to move the active - * position past the last position on the line, then the active position - * stops at the last position on the line. - * - * @args[0] defines the horizontal position. 0 is treated as 1. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - screen_cursor_clear_wrap(screen); - screen_cursor_set(screen, num - 1, screen->state.cursor_y); - - return 0; -} - -static int screen_HPR(term_screen *screen, const term_seq *seq) { - /* - * HPR - horizontal-position-relative - * HPR causes the active position to be moved to the n-th following - * horizontal position of the active line. If an attempt is made to move - * the active position past the last position on the line, then the - * active position stops at the last position on the line. - * - * @args[0] defines the horizontal position. 0 is treated as 1. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - screen_cursor_clear_wrap(screen); - screen_cursor_right(screen, num); - - return 0; -} - -static int screen_HT(term_screen *screen, const term_seq *seq) { - /* - * HT - horizontal-tab - * Moves the cursor to the next tab stop. If there are no more tab - * stops, the cursor moves to the right margin. HT does not cause text - * to auto wrap. - */ - - screen_cursor_clear_wrap(screen); - screen_cursor_right_tab(screen, 1); - - return 0; -} - -static int screen_HTS(term_screen *screen, const term_seq *seq) { - /* - * HTS - horizontal-tab-set - * HTS sets a horizontal tab stop at the column position indicated by - * the value of the active column when the terminal receives an HTS. - * - * Executing an HTS does not effect the other horizontal tab stop - * settings. - */ - - unsigned int pos; - - pos = screen->state.cursor_x; - if (screen->page->width > 0) - screen->tabs[pos / 8] |= 1U << (pos % 8); - - return 0; -} - -static int screen_HVP(term_screen *screen, const term_seq *seq) { - /* - * HVP - horizontal-and-vertical-position - * This control function works the same as the cursor position (CUP) - * function. Origin mode (DECOM) selects line numbering and the ability - * to move the cursor into margins. - * - * Defaults: - * args[0]: 1 - * args[1]: 1 - */ - - return screen_CUP(screen, seq); -} - -static int screen_ICH(term_screen *screen, const term_seq *seq) { - /* - * ICH - insert-character - * This control function inserts one or more space (SP) characters - * starting at the cursor position. @args[0] is the number of characters - * to insert. 0 is treated as 1. - * - * The ICH sequence inserts blank characters with the normal - * character attribute. The cursor remains at the beginning of the blank - * characters. Text between the cursor and right margin moves to the - * right. Characters scrolled past the right margin are lost. ICH has no - * effect outside the scrolling margins. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - screen_cursor_clear_wrap(screen); - term_page_insert_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age); - - return 0; -} - -static int screen_IL(term_screen *screen, const term_seq *seq) { - /* - * IL - insert-line - * This control function inserts one or more blank lines, starting at - * the cursor. @args[0] is the number of lines to insert. 0 is treated - * as 1. - * - * As lines are inserted, lines below the cursor and in the scrolling - * region move down. Lines scrolled off the page are lost. IL has no - * effect outside the page margins. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - screen_cursor_clear_wrap(screen); - term_page_insert_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age); - - return 0; -} - -static int screen_IND(term_screen *screen, const term_seq *seq) { - /* - * IND - index - * IND moves the cursor down one line in the same column. If the cursor - * is at the bottom margin, then the screen performs a scroll-up. - */ - - screen_cursor_down(screen, 1, true); - - return 0; -} - -static int screen_LF(term_screen *screen, const term_seq *seq) { - /* - * LF - line-feed - * Causes a line feed or a new line operation, depending on the setting - * of line feed/new line mode. - */ - - screen_cursor_down(screen, 1, true); - if (screen->flags & TERM_FLAG_NEWLINE_MODE) - screen_cursor_left(screen, screen->state.cursor_x); - - return 0; -} - -static int screen_LS1R(term_screen *screen, const term_seq *seq) { - /* - * LS1R - locking-shift-1-right - * Map G1 into GR. - */ - - screen->state.gr = &screen->g1; - - return 0; -} - -static int screen_LS2(term_screen *screen, const term_seq *seq) { - /* - * LS2 - locking-shift-2 - * Map G2 into GL. - */ - - screen->state.gl = &screen->g2; - - return 0; -} - -static int screen_LS2R(term_screen *screen, const term_seq *seq) { - /* - * LS2R - locking-shift-2-right - * Map G2 into GR. - */ - - screen->state.gr = &screen->g2; - - return 0; -} - -static int screen_LS3(term_screen *screen, const term_seq *seq) { - /* - * LS3 - locking-shift-3 - * Map G3 into GL. - */ - - screen->state.gl = &screen->g3; - - return 0; -} - -static int screen_LS3R(term_screen *screen, const term_seq *seq) { - /* - * LS3R - locking-shift-3-right - * Map G3 into GR. - */ - - screen->state.gr = &screen->g3; - - return 0; -} - -static int screen_MC_ANSI(term_screen *screen, const term_seq *seq) { - /* - * MC_ANSI - media-copy-ansi - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_MC_DEC(term_screen *screen, const term_seq *seq) { - /* - * MC_DEC - media-copy-dec - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_NEL(term_screen *screen, const term_seq *seq) { - /* - * NEL - next-line - * Moves cursor to first position on next line. If cursor is at bottom - * margin, then screen performs a scroll-up. - */ - - screen_cursor_clear_wrap(screen); - screen_cursor_down(screen, 1, true); - screen_cursor_set(screen, 0, screen->state.cursor_y); - - return 0; -} - -static int screen_NP(term_screen *screen, const term_seq *seq) { - /* - * NP - next-page - * This control function moves the cursor forward to the home position - * on one of the following pages in page memory. If there is only one - * page, then the terminal ignores NP. - * If NP tries to move the cursor past the last page in memory, then the - * cursor stops at the last page. - * - * @args[0] defines the number of pages to forward. 0 is treated as 1. - * - * Defaults: - * args[0]: 1 - * - * Probably not worth implementing. We only support a single page. - */ - - return 0; -} - -static int screen_NULL(term_screen *screen, const term_seq *seq) { - /* - * NULL - null - * The NULL operation does nothing. ASCII NULL is always ignored. - */ - - return 0; -} - -static int screen_PP(term_screen *screen, const term_seq *seq) { - /* - * PP - preceding-page - * This control function moves the cursor backward to the home position - * on one of the preceding pages in page memory. If there is only one - * page, then the terminal ignores PP. - * If PP tries to move the cursor back farther than the first page in - * memory, then the cursor stops at the first page. - * - * @args[0] defines the number of pages to go backwards. 0 is treated - * as 1. - * - * Defaults: - * args[0]: 1 - * - * Probably not worth implementing. We only support a single page. - */ - - return 0; -} - -static int screen_PPA(term_screen *screen, const term_seq *seq) { - /* - * PPA - page-position-absolute - * This control function can move the cursor to the corresponding row - * and column on any page in page memory. You select the page by its - * number. If there is only one page, then the terminal ignores PPA. - * - * @args[0] is the number of the page to move the cursor to. If it is - * greater than the number of the last page in memory, then the cursor - * stops at the last page. If it is less than the number of the first - * page, then the cursor stops at the first page. - * - * Defaults: - * args[0]: 1 - * - * Probably not worth implementing. We only support a single page. - */ - - return 0; -} - -static int screen_PPB(term_screen *screen, const term_seq *seq) { - /* - * PPB - page-position-backward - * This control function moves the cursor backward to the corresponding - * row and column on one of the preceding pages in page memory. If there - * is only one page, then the terminal ignores PPB. - * - * @args[0] indicates the number of pages to move the cursor backward. - * If it tries to move the cursor back farther than the first page in - * memory, then the cursor stops at the first page. 0 is treated as 1. - * - * Defaults: - * args[0]: 1 - * - * Probably not worth implementing. We only support a single page. - */ - - return 0; -} - -static int screen_PPR(term_screen *screen, const term_seq *seq) { - /* - * PPR - page-position-relative - * This control function moves the cursor forward to the corresponding - * row and column on one of the following pages in page memory. If there - * is only one page, then the terminal ignores PPR. - * - * @args[0] indicates how many pages to move the cursor forward. If it - * tries to move the cursor beyond the last page in memory, then the - * cursor stops at the last page. 0 is treated as 1. - * - * Defaults: - * args[0]: 1 - * - * Probably not worth implementing. We only support a single page. - */ - - return 0; -} - -static int screen_RC(term_screen *screen, const term_seq *seq) { - /* - * RC - restore-cursor - */ - - return screen_DECRC(screen, seq); -} - -static int screen_REP(term_screen *screen, const term_seq *seq) { - /* - * REP - repeat - * Repeat the preceding graphics-character the given number of times. - * @args[0] specifies how often it shall be repeated. 0 is treated as 1. - * - * Defaults: - * args[0]: 1 - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_RI(term_screen *screen, const term_seq *seq) { - /* - * RI - reverse-index - * Moves the cursor up one line in the same column. If the cursor is at - * the top margin, the page scrolls down. - */ - - screen_cursor_up(screen, 1, true); - - return 0; -} - -static int screen_RIS(term_screen *screen, const term_seq *seq) { - /* - * RIS - reset-to-initial-state - * This control function causes a nonvolatile memory (NVR) recall to - * occur. RIS replaces all set-up features with their saved settings. - * - * The terminal stores these saved settings in NVR memory. The saved - * setting for a feature is the same as the factory-default setting, - * unless you saved a new setting. - */ - - term_screen_hard_reset(screen); - - return 0; -} - -static int screen_RM_ANSI(term_screen *screen, const term_seq *seq) { - /* - * RM_ANSI - reset-mode-ansi - * - * TODO: implement (see VT510rm manual) - */ - - unsigned int i; - - for (i = 0; i < seq->n_args; ++i) - screen_mode_change_ansi(screen, seq->args[i], false); - - return 0; -} - -static int screen_RM_DEC(term_screen *screen, const term_seq *seq) { - /* - * RM_DEC - reset-mode-dec - * This is the same as RM_ANSI but for DEC modes. - */ - - unsigned int i; - - for (i = 0; i < seq->n_args; ++i) - screen_mode_change_dec(screen, seq->args[i], false); - - return 0; -} - -static int screen_S7C1T(term_screen *screen, const term_seq *seq) { - /* - * S7C1T - set-7bit-c1-terminal - * This causes the terminal to start sending C1 controls as 7bit - * sequences instead of 8bit C1 controls. - * This is ignored if the terminal is below level-2 emulation mode - * (VT100 and below), the terminal already sends 7bit controls then. - */ - - if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100) - screen->flags |= TERM_FLAG_7BIT_MODE; - - return 0; -} - -static int screen_S8C1T(term_screen *screen, const term_seq *seq) { - /* - * S8C1T - set-8bit-c1-terminal - * This causes the terminal to start sending C1 controls as 8bit C1 - * control instead of 7bit sequences. - * This is ignored if the terminal is below level-2 emulation mode - * (VT100 and below). The terminal always sends 7bit controls in those - * modes. - */ - - if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100) - screen->flags &= ~TERM_FLAG_7BIT_MODE; - - return 0; -} - -static int screen_SCS(term_screen *screen, const term_seq *seq) { - /* - * SCS - select-character-set - * Designate character sets to G-sets. The mapping from intermediates - * and terminal characters in the escape sequence to G-sets and - * character-sets is non-trivial and implemented separately. See there - * for more information. - * This call simply sets the selected G-set to the desired - * character-set. - */ - - term_charset *cs = NULL; - - /* TODO: support more of them? */ - switch (seq->charset) { - case TERM_CHARSET_ISO_LATIN1_SUPPLEMENTAL: - case TERM_CHARSET_ISO_LATIN2_SUPPLEMENTAL: - case TERM_CHARSET_ISO_LATIN5_SUPPLEMENTAL: - case TERM_CHARSET_ISO_GREEK_SUPPLEMENTAL: - case TERM_CHARSET_ISO_HEBREW_SUPPLEMENTAL: - case TERM_CHARSET_ISO_LATIN_CYRILLIC: - break; - - case TERM_CHARSET_DEC_SPECIAL_GRAPHIC: - cs = &term_dec_special_graphics; - break; - case TERM_CHARSET_DEC_SUPPLEMENTAL: - cs = &term_dec_supplemental_graphics; - break; - case TERM_CHARSET_DEC_TECHNICAL: - case TERM_CHARSET_CYRILLIC_DEC: - case TERM_CHARSET_DUTCH_NRCS: - case TERM_CHARSET_FINNISH_NRCS: - case TERM_CHARSET_FRENCH_NRCS: - case TERM_CHARSET_FRENCH_CANADIAN_NRCS: - case TERM_CHARSET_GERMAN_NRCS: - case TERM_CHARSET_GREEK_DEC: - case TERM_CHARSET_GREEK_NRCS: - case TERM_CHARSET_HEBREW_DEC: - case TERM_CHARSET_HEBREW_NRCS: - case TERM_CHARSET_ITALIAN_NRCS: - case TERM_CHARSET_NORWEGIAN_DANISH_NRCS: - case TERM_CHARSET_PORTUGUESE_NRCS: - case TERM_CHARSET_RUSSIAN_NRCS: - case TERM_CHARSET_SCS_NRCS: - case TERM_CHARSET_SPANISH_NRCS: - case TERM_CHARSET_SWEDISH_NRCS: - case TERM_CHARSET_SWISS_NRCS: - case TERM_CHARSET_TURKISH_DEC: - case TERM_CHARSET_TURKISH_NRCS: - break; - - case TERM_CHARSET_USERPREF_SUPPLEMENTAL: - break; - } - - if (seq->intermediates & TERM_SEQ_FLAG_POPEN) - screen->g0 = cs ? : &term_unicode_lower; - else if (seq->intermediates & TERM_SEQ_FLAG_PCLOSE) - screen->g1 = cs ? : &term_unicode_upper; - else if (seq->intermediates & TERM_SEQ_FLAG_MULT) - screen->g2 = cs ? : &term_unicode_lower; - else if (seq->intermediates & TERM_SEQ_FLAG_PLUS) - screen->g3 = cs ? : &term_unicode_upper; - else if (seq->intermediates & TERM_SEQ_FLAG_MINUS) - screen->g1 = cs ? : &term_unicode_upper; - else if (seq->intermediates & TERM_SEQ_FLAG_DOT) - screen->g2 = cs ? : &term_unicode_lower; - else if (seq->intermediates & TERM_SEQ_FLAG_SLASH) - screen->g3 = cs ? : &term_unicode_upper; - - return 0; -} - -static int screen_SD(term_screen *screen, const term_seq *seq) { - /* - * SD - scroll-down - * This control function moves the user window down a specified number - * of lines in page memory. - * @args[0] is the number of lines to move the - * user window up in page memory. New lines appear at the top of the - * display. Old lines disappear at the bottom of the display. You - * cannot pan past the top margin of the current page. 0 is treated - * as 1. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - term_page_scroll_down(screen->page, num, &screen->state.attr, screen->age, NULL); - - return 0; -} - -static int screen_SGR(term_screen *screen, const term_seq *seq) { - /* - * SGR - select-graphics-rendition - */ - - term_color *dst; - unsigned int i, code; - int v; - - if (seq->n_args < 1) { - zero(screen->state.attr); - return 0; - } - - for (i = 0; i < seq->n_args; ++i) { - v = seq->args[i]; - switch (v) { - case 1: - screen->state.attr.bold = 1; - break; - case 3: - screen->state.attr.italic = 1; - break; - case 4: - screen->state.attr.underline = 1; - break; - case 5: - screen->state.attr.blink = 1; - break; - case 7: - screen->state.attr.inverse = 1; - break; - case 8: - screen->state.attr.hidden = 1; - break; - case 22: - screen->state.attr.bold = 0; - break; - case 23: - screen->state.attr.italic = 0; - break; - case 24: - screen->state.attr.underline = 0; - break; - case 25: - screen->state.attr.blink = 0; - break; - case 27: - screen->state.attr.inverse = 0; - break; - case 28: - screen->state.attr.hidden = 0; - break; - case 30 ... 37: - screen->state.attr.fg.ccode = v - 30 + TERM_CCODE_BLACK; - break; - case 39: - screen->state.attr.fg.ccode = 0; - break; - case 40 ... 47: - screen->state.attr.bg.ccode = v - 40 + TERM_CCODE_BLACK; - break; - case 49: - screen->state.attr.bg.ccode = 0; - break; - case 90 ... 97: - screen->state.attr.fg.ccode = v - 90 + TERM_CCODE_LIGHT_BLACK; - break; - case 100 ... 107: - screen->state.attr.bg.ccode = v - 100 + TERM_CCODE_LIGHT_BLACK; - break; - case 38: - /* fallthrough */ - case 48: - - if (v == 38) - dst = &screen->state.attr.fg; - else - dst = &screen->state.attr.bg; - - ++i; - if (i >= seq->n_args) - break; - - switch (seq->args[i]) { - case 2: - /* 24bit-color support */ - - i += 3; - if (i >= seq->n_args) - break; - - dst->ccode = TERM_CCODE_RGB; - dst->red = (seq->args[i - 2] >= 0) ? seq->args[i - 2] : 0; - dst->green = (seq->args[i - 1] >= 0) ? seq->args[i - 1] : 0; - dst->blue = (seq->args[i] >= 0) ? seq->args[i] : 0; - - break; - case 5: - /* 256-color support */ - - ++i; - if (i >= seq->n_args || seq->args[i] < 0) - break; - - dst->ccode = TERM_CCODE_256; - code = seq->args[i]; - dst->c256 = code < 256 ? code : 0; - - break; - } - - break; - case -1: - /* fallthrough */ - case 0: - zero(screen->state.attr); - break; - } - } - - return 0; -} - -static int screen_SI(term_screen *screen, const term_seq *seq) { - /* - * SI - shift-in - * Map G0 into GL. - */ - - screen->state.gl = &screen->g0; - - return 0; -} - -static int screen_SM_ANSI(term_screen *screen, const term_seq *seq) { - /* - * SM_ANSI - set-mode-ansi - * - * TODO: implement - */ - - unsigned int i; - - for (i = 0; i < seq->n_args; ++i) - screen_mode_change_ansi(screen, seq->args[i], true); - - return 0; -} - -static int screen_SM_DEC(term_screen *screen, const term_seq *seq) { - /* - * SM_DEC - set-mode-dec - * This is the same as SM_ANSI but for DEC modes. - */ - - unsigned int i; - - for (i = 0; i < seq->n_args; ++i) - screen_mode_change_dec(screen, seq->args[i], true); - - return 0; -} - -static int screen_SO(term_screen *screen, const term_seq *seq) { - /* - * SO - shift-out - * Map G1 into GL. - */ - - screen->state.gl = &screen->g1; - - return 0; -} - -static int screen_SPA(term_screen *screen, const term_seq *seq) { - /* - * SPA - start-of-protected-area - * - * TODO: What is this? - */ - - return 0; -} - -static int screen_SS2(term_screen *screen, const term_seq *seq) { - /* - * SS2 - single-shift-2 - * Temporarily map G2 into GL for the next graphics character. - */ - - screen->state.glt = &screen->g2; - - return 0; -} - -static int screen_SS3(term_screen *screen, const term_seq *seq) { - /* - * SS3 - single-shift-3 - * Temporarily map G3 into GL for the next graphics character - */ - - screen->state.glt = &screen->g3; - - return 0; -} - -static int screen_ST(term_screen *screen, const term_seq *seq) { - /* - * ST - string-terminator - * The string-terminator is usually part of control-sequences and - * handled by the parser. In all other situations it is silently - * ignored. - */ - - return 0; -} - -static int screen_SU(term_screen *screen, const term_seq *seq) { - /* - * SU - scroll-up - * This control function moves the user window up a specified number of - * lines in page memory. - * @args[0] is the number of lines to move the - * user window down in page memory. New lines appear at the bottom of - * the display. Old lines disappear at the top of the display. You - * cannot pan past the bottom margin of the current page. 0 is treated - * as 1. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - term_page_scroll_up(screen->page, num, &screen->state.attr, screen->age, screen->history); - - return 0; -} - -static int screen_SUB(term_screen *screen, const term_seq *seq) { - /* - * SUB - substitute - * Cancel the current control-sequence and print a replacement - * character. Our parser already handles this so all we have to do is - * print the replacement character. - */ - - static const term_seq rep = { - .type = TERM_SEQ_GRAPHIC, - .command = TERM_CMD_GRAPHIC, - .terminator = 0xfffd, - }; - - return screen_GRAPHIC(screen, &rep); -} - -static int screen_TBC(term_screen *screen, const term_seq *seq) { - /* - * TBC - tab-clear - * This clears tab-stops. If @args[0] is 0, the tab-stop at the current - * cursor position is cleared. If it is 3, all tab stops are cleared. - * - * Defaults: - * args[0]: 0 - */ - - unsigned int mode = 0, pos; - - if (seq->args[0] > 0) - mode = seq->args[0]; - - switch (mode) { - case 0: - pos = screen->state.cursor_x; - if (screen->page->width > 0) - screen->tabs[pos / 8] &= ~(1U << (pos % 8)); - break; - case 3: - if (screen->page->width > 0) - memzero(screen->tabs, (screen->page->width + 7) / 8); - break; - } - - return 0; -} - -static int screen_VPA(term_screen *screen, const term_seq *seq) { - /* - * VPA - vertical-line-position-absolute - * VPA causes the active position to be moved to the corresponding - * horizontal position. @args[0] specifies the line to jump to. If an - * attempt is made to move the active position below the last line, then - * the active position stops on the last line. 0 is treated as 1. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int pos = 1; - - if (seq->args[0] > 0) - pos = seq->args[0]; - - screen_cursor_clear_wrap(screen); - screen_cursor_set_rel(screen, screen->state.cursor_x, pos - 1); - - return 0; -} - -static int screen_VPR(term_screen *screen, const term_seq *seq) { - /* - * VPR - vertical-line-position-relative - * VPR causes the active position to be moved to the corresponding - * horizontal position. @args[0] specifies the number of lines to jump - * down relative to the current cursor position. If an attempt is made - * to move the active position below the last line, the active position - * stops at the last line. 0 is treated as 1. - * - * Defaults: - * args[0]: 1 - */ - - unsigned int num = 1; - - if (seq->args[0] > 0) - num = seq->args[0]; - - screen_cursor_clear_wrap(screen); - screen_cursor_down(screen, num, false); - - return 0; -} - -static int screen_VT(term_screen *screen, const term_seq *seq) { - /* - * VT - vertical-tab - * This causes a vertical jump by one line. Terminals treat it exactly - * the same as LF. - */ - - return screen_LF(screen, seq); -} - -static int screen_XTERM_CLLHP(term_screen *screen, const term_seq *seq) { - /* - * XTERM_CLLHP - xterm-cursor-lower-left-hp-bugfix - * Move the cursor to the lower-left corner of the page. This is an HP - * bugfix by xterm. - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_XTERM_IHMT(term_screen *screen, const term_seq *seq) { - /* - * XTERM_IHMT - xterm-initiate-highlight-mouse-tracking - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_XTERM_MLHP(term_screen *screen, const term_seq *seq) { - /* - * XTERM_MLHP - xterm-memory-lock-hp-bugfix - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_XTERM_MUHP(term_screen *screen, const term_seq *seq) { - /* - * XTERM_MUHP - xterm-memory-unlock-hp-bugfix - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_XTERM_RPM(term_screen *screen, const term_seq *seq) { - /* - * XTERM_RPM - xterm-restore-private-mode - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_XTERM_RRV(term_screen *screen, const term_seq *seq) { - /* - * XTERM_RRV - xterm-reset-resource-value - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_XTERM_RTM(term_screen *screen, const term_seq *seq) { - /* - * XTERM_RTM - xterm-reset-title-mode - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_XTERM_SACL1(term_screen *screen, const term_seq *seq) { - /* - * XTERM_SACL1 - xterm-set-ansi-conformance-level-1 - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_XTERM_SACL2(term_screen *screen, const term_seq *seq) { - /* - * XTERM_SACL2 - xterm-set-ansi-conformance-level-2 - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_XTERM_SACL3(term_screen *screen, const term_seq *seq) { - /* - * XTERM_SACL3 - xterm-set-ansi-conformance-level-3 - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_XTERM_SDCS(term_screen *screen, const term_seq *seq) { - /* - * XTERM_SDCS - xterm-set-default-character-set - * Select the default character set. We treat this the same as UTF-8 as - * this is our default character set. As we always use UTF-8, this - * becomes as no-op. - */ - - return 0; -} - -static int screen_XTERM_SGFX(term_screen *screen, const term_seq *seq) { - /* - * XTERM_SGFX - xterm-sixel-graphics - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_XTERM_SPM(term_screen *screen, const term_seq *seq) { - /* - * XTERM_SPM - xterm-set-private-mode - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_XTERM_SRV(term_screen *screen, const term_seq *seq) { - /* - * XTERM_SRV - xterm-set-resource-value - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_XTERM_STM(term_screen *screen, const term_seq *seq) { - /* - * XTERM_STM - xterm-set-title-mode - * - * Probably not worth implementing. - */ - - return 0; -} - -static int screen_XTERM_SUCS(term_screen *screen, const term_seq *seq) { - /* - * XTERM_SUCS - xterm-select-utf8-character-set - * Select UTF-8 as character set. This is our default on only character - * set. Hence, this is a no-op. - */ - - return 0; -} - -static int screen_XTERM_WM(term_screen *screen, const term_seq *seq) { - /* - * XTERM_WM - xterm-window-management - * - * Probably not worth implementing. - */ - - return 0; -} - -/* - * Feeding data - * The screen_feed_*() handlers take data from the user and feed it into the - * screen. Once the parser has detected a sequence, we parse the command-type - * and forward it to the command-dispatchers. - */ - -static int screen_feed_cmd(term_screen *screen, const term_seq *seq) { - switch (seq->command) { - case TERM_CMD_GRAPHIC: - return screen_GRAPHIC(screen, seq); - case TERM_CMD_BEL: - return screen_BEL(screen, seq); - case TERM_CMD_BS: - return screen_BS(screen, seq); - case TERM_CMD_CBT: - return screen_CBT(screen, seq); - case TERM_CMD_CHA: - return screen_CHA(screen, seq); - case TERM_CMD_CHT: - return screen_CHT(screen, seq); - case TERM_CMD_CNL: - return screen_CNL(screen, seq); - case TERM_CMD_CPL: - return screen_CPL(screen, seq); - case TERM_CMD_CR: - return screen_CR(screen, seq); - case TERM_CMD_CUB: - return screen_CUB(screen, seq); - case TERM_CMD_CUD: - return screen_CUD(screen, seq); - case TERM_CMD_CUF: - return screen_CUF(screen, seq); - case TERM_CMD_CUP: - return screen_CUP(screen, seq); - case TERM_CMD_CUU: - return screen_CUU(screen, seq); - case TERM_CMD_DA1: - return screen_DA1(screen, seq); - case TERM_CMD_DA2: - return screen_DA2(screen, seq); - case TERM_CMD_DA3: - return screen_DA3(screen, seq); - case TERM_CMD_DC1: - return screen_DC1(screen, seq); - case TERM_CMD_DC3: - return screen_DC3(screen, seq); - case TERM_CMD_DCH: - return screen_DCH(screen, seq); - case TERM_CMD_DECALN: - return screen_DECALN(screen, seq); - case TERM_CMD_DECANM: - return screen_DECANM(screen, seq); - case TERM_CMD_DECBI: - return screen_DECBI(screen, seq); - case TERM_CMD_DECCARA: - return screen_DECCARA(screen, seq); - case TERM_CMD_DECCRA: - return screen_DECCRA(screen, seq); - case TERM_CMD_DECDC: - return screen_DECDC(screen, seq); - case TERM_CMD_DECDHL_BH: - return screen_DECDHL_BH(screen, seq); - case TERM_CMD_DECDHL_TH: - return screen_DECDHL_TH(screen, seq); - case TERM_CMD_DECDWL: - return screen_DECDWL(screen, seq); - case TERM_CMD_DECEFR: - return screen_DECEFR(screen, seq); - case TERM_CMD_DECELF: - return screen_DECELF(screen, seq); - case TERM_CMD_DECELR: - return screen_DECELR(screen, seq); - case TERM_CMD_DECERA: - return screen_DECERA(screen, seq); - case TERM_CMD_DECFI: - return screen_DECFI(screen, seq); - case TERM_CMD_DECFRA: - return screen_DECFRA(screen, seq); - case TERM_CMD_DECIC: - return screen_DECIC(screen, seq); - case TERM_CMD_DECID: - return screen_DECID(screen, seq); - case TERM_CMD_DECINVM: - return screen_DECINVM(screen, seq); - case TERM_CMD_DECKBD: - return screen_DECKBD(screen, seq); - case TERM_CMD_DECKPAM: - return screen_DECKPAM(screen, seq); - case TERM_CMD_DECKPNM: - return screen_DECKPNM(screen, seq); - case TERM_CMD_DECLFKC: - return screen_DECLFKC(screen, seq); - case TERM_CMD_DECLL: - return screen_DECLL(screen, seq); - case TERM_CMD_DECLTOD: - return screen_DECLTOD(screen, seq); - case TERM_CMD_DECPCTERM: - return screen_DECPCTERM(screen, seq); - case TERM_CMD_DECPKA: - return screen_DECPKA(screen, seq); - case TERM_CMD_DECPKFMR: - return screen_DECPKFMR(screen, seq); - case TERM_CMD_DECRARA: - return screen_DECRARA(screen, seq); - case TERM_CMD_DECRC: - return screen_DECRC(screen, seq); - case TERM_CMD_DECREQTPARM: - return screen_DECREQTPARM(screen, seq); - case TERM_CMD_DECRPKT: - return screen_DECRPKT(screen, seq); - case TERM_CMD_DECRQCRA: - return screen_DECRQCRA(screen, seq); - case TERM_CMD_DECRQDE: - return screen_DECRQDE(screen, seq); - case TERM_CMD_DECRQKT: - return screen_DECRQKT(screen, seq); - case TERM_CMD_DECRQLP: - return screen_DECRQLP(screen, seq); - case TERM_CMD_DECRQM_ANSI: - return screen_DECRQM_ANSI(screen, seq); - case TERM_CMD_DECRQM_DEC: - return screen_DECRQM_DEC(screen, seq); - case TERM_CMD_DECRQPKFM: - return screen_DECRQPKFM(screen, seq); - case TERM_CMD_DECRQPSR: - return screen_DECRQPSR(screen, seq); - case TERM_CMD_DECRQTSR: - return screen_DECRQTSR(screen, seq); - case TERM_CMD_DECRQUPSS: - return screen_DECRQUPSS(screen, seq); - case TERM_CMD_DECSACE: - return screen_DECSACE(screen, seq); - case TERM_CMD_DECSASD: - return screen_DECSASD(screen, seq); - case TERM_CMD_DECSC: - return screen_DECSC(screen, seq); - case TERM_CMD_DECSCA: - return screen_DECSCA(screen, seq); - case TERM_CMD_DECSCL: - return screen_DECSCL(screen, seq); - case TERM_CMD_DECSCP: - return screen_DECSCP(screen, seq); - case TERM_CMD_DECSCPP: - return screen_DECSCPP(screen, seq); - case TERM_CMD_DECSCS: - return screen_DECSCS(screen, seq); - case TERM_CMD_DECSCUSR: - return screen_DECSCUSR(screen, seq); - case TERM_CMD_DECSDDT: - return screen_DECSDDT(screen, seq); - case TERM_CMD_DECSDPT: - return screen_DECSDPT(screen, seq); - case TERM_CMD_DECSED: - return screen_DECSED(screen, seq); - case TERM_CMD_DECSEL: - return screen_DECSEL(screen, seq); - case TERM_CMD_DECSERA: - return screen_DECSERA(screen, seq); - case TERM_CMD_DECSFC: - return screen_DECSFC(screen, seq); - case TERM_CMD_DECSKCV: - return screen_DECSKCV(screen, seq); - case TERM_CMD_DECSLCK: - return screen_DECSLCK(screen, seq); - case TERM_CMD_DECSLE: - return screen_DECSLE(screen, seq); - case TERM_CMD_DECSLPP: - return screen_DECSLPP(screen, seq); - case TERM_CMD_DECSLRM_OR_SC: - return screen_DECSLRM_OR_SC(screen, seq); - case TERM_CMD_DECSMBV: - return screen_DECSMBV(screen, seq); - case TERM_CMD_DECSMKR: - return screen_DECSMKR(screen, seq); - case TERM_CMD_DECSNLS: - return screen_DECSNLS(screen, seq); - case TERM_CMD_DECSPP: - return screen_DECSPP(screen, seq); - case TERM_CMD_DECSPPCS: - return screen_DECSPPCS(screen, seq); - case TERM_CMD_DECSPRTT: - return screen_DECSPRTT(screen, seq); - case TERM_CMD_DECSR: - return screen_DECSR(screen, seq); - case TERM_CMD_DECSRFR: - return screen_DECSRFR(screen, seq); - case TERM_CMD_DECSSCLS: - return screen_DECSSCLS(screen, seq); - case TERM_CMD_DECSSDT: - return screen_DECSSDT(screen, seq); - case TERM_CMD_DECSSL: - return screen_DECSSL(screen, seq); - case TERM_CMD_DECST8C: - return screen_DECST8C(screen, seq); - case TERM_CMD_DECSTBM: - return screen_DECSTBM(screen, seq); - case TERM_CMD_DECSTR: - return screen_DECSTR(screen, seq); - case TERM_CMD_DECSTRL: - return screen_DECSTRL(screen, seq); - case TERM_CMD_DECSWBV: - return screen_DECSWBV(screen, seq); - case TERM_CMD_DECSWL: - return screen_DECSWL(screen, seq); - case TERM_CMD_DECTID: - return screen_DECTID(screen, seq); - case TERM_CMD_DECTME: - return screen_DECTME(screen, seq); - case TERM_CMD_DECTST: - return screen_DECTST(screen, seq); - case TERM_CMD_DL: - return screen_DL(screen, seq); - case TERM_CMD_DSR_ANSI: - return screen_DSR_ANSI(screen, seq); - case TERM_CMD_DSR_DEC: - return screen_DSR_DEC(screen, seq); - case TERM_CMD_ECH: - return screen_ECH(screen, seq); - case TERM_CMD_ED: - return screen_ED(screen, seq); - case TERM_CMD_EL: - return screen_EL(screen, seq); - case TERM_CMD_ENQ: - return screen_ENQ(screen, seq); - case TERM_CMD_EPA: - return screen_EPA(screen, seq); - case TERM_CMD_FF: - return screen_FF(screen, seq); - case TERM_CMD_HPA: - return screen_HPA(screen, seq); - case TERM_CMD_HPR: - return screen_HPR(screen, seq); - case TERM_CMD_HT: - return screen_HT(screen, seq); - case TERM_CMD_HTS: - return screen_HTS(screen, seq); - case TERM_CMD_HVP: - return screen_HVP(screen, seq); - case TERM_CMD_ICH: - return screen_ICH(screen, seq); - case TERM_CMD_IL: - return screen_IL(screen, seq); - case TERM_CMD_IND: - return screen_IND(screen, seq); - case TERM_CMD_LF: - return screen_LF(screen, seq); - case TERM_CMD_LS1R: - return screen_LS1R(screen, seq); - case TERM_CMD_LS2: - return screen_LS2(screen, seq); - case TERM_CMD_LS2R: - return screen_LS2R(screen, seq); - case TERM_CMD_LS3: - return screen_LS3(screen, seq); - case TERM_CMD_LS3R: - return screen_LS3R(screen, seq); - case TERM_CMD_MC_ANSI: - return screen_MC_ANSI(screen, seq); - case TERM_CMD_MC_DEC: - return screen_MC_DEC(screen, seq); - case TERM_CMD_NEL: - return screen_NEL(screen, seq); - case TERM_CMD_NP: - return screen_NP(screen, seq); - case TERM_CMD_NULL: - return screen_NULL(screen, seq); - case TERM_CMD_PP: - return screen_PP(screen, seq); - case TERM_CMD_PPA: - return screen_PPA(screen, seq); - case TERM_CMD_PPB: - return screen_PPB(screen, seq); - case TERM_CMD_PPR: - return screen_PPR(screen, seq); - case TERM_CMD_RC: - return screen_RC(screen, seq); - case TERM_CMD_REP: - return screen_REP(screen, seq); - case TERM_CMD_RI: - return screen_RI(screen, seq); - case TERM_CMD_RIS: - return screen_RIS(screen, seq); - case TERM_CMD_RM_ANSI: - return screen_RM_ANSI(screen, seq); - case TERM_CMD_RM_DEC: - return screen_RM_DEC(screen, seq); - case TERM_CMD_S7C1T: - return screen_S7C1T(screen, seq); - case TERM_CMD_S8C1T: - return screen_S8C1T(screen, seq); - case TERM_CMD_SCS: - return screen_SCS(screen, seq); - case TERM_CMD_SD: - return screen_SD(screen, seq); - case TERM_CMD_SGR: - return screen_SGR(screen, seq); - case TERM_CMD_SI: - return screen_SI(screen, seq); - case TERM_CMD_SM_ANSI: - return screen_SM_ANSI(screen, seq); - case TERM_CMD_SM_DEC: - return screen_SM_DEC(screen, seq); - case TERM_CMD_SO: - return screen_SO(screen, seq); - case TERM_CMD_SPA: - return screen_SPA(screen, seq); - case TERM_CMD_SS2: - return screen_SS2(screen, seq); - case TERM_CMD_SS3: - return screen_SS3(screen, seq); - case TERM_CMD_ST: - return screen_ST(screen, seq); - case TERM_CMD_SU: - return screen_SU(screen, seq); - case TERM_CMD_SUB: - return screen_SUB(screen, seq); - case TERM_CMD_TBC: - return screen_TBC(screen, seq); - case TERM_CMD_VPA: - return screen_VPA(screen, seq); - case TERM_CMD_VPR: - return screen_VPR(screen, seq); - case TERM_CMD_VT: - return screen_VT(screen, seq); - case TERM_CMD_XTERM_CLLHP: - return screen_XTERM_CLLHP(screen, seq); - case TERM_CMD_XTERM_IHMT: - return screen_XTERM_IHMT(screen, seq); - case TERM_CMD_XTERM_MLHP: - return screen_XTERM_MLHP(screen, seq); - case TERM_CMD_XTERM_MUHP: - return screen_XTERM_MUHP(screen, seq); - case TERM_CMD_XTERM_RPM: - return screen_XTERM_RPM(screen, seq); - case TERM_CMD_XTERM_RRV: - return screen_XTERM_RRV(screen, seq); - case TERM_CMD_XTERM_RTM: - return screen_XTERM_RTM(screen, seq); - case TERM_CMD_XTERM_SACL1: - return screen_XTERM_SACL1(screen, seq); - case TERM_CMD_XTERM_SACL2: - return screen_XTERM_SACL2(screen, seq); - case TERM_CMD_XTERM_SACL3: - return screen_XTERM_SACL3(screen, seq); - case TERM_CMD_XTERM_SDCS: - return screen_XTERM_SDCS(screen, seq); - case TERM_CMD_XTERM_SGFX: - return screen_XTERM_SGFX(screen, seq); - case TERM_CMD_XTERM_SPM: - return screen_XTERM_SPM(screen, seq); - case TERM_CMD_XTERM_SRV: - return screen_XTERM_SRV(screen, seq); - case TERM_CMD_XTERM_STM: - return screen_XTERM_STM(screen, seq); - case TERM_CMD_XTERM_SUCS: - return screen_XTERM_SUCS(screen, seq); - case TERM_CMD_XTERM_WM: - return screen_XTERM_WM(screen, seq); - } - - return 0; -} - -unsigned int term_screen_get_width(term_screen *screen) { - assert_return(screen, -EINVAL); - - return screen->page->width; -} - -unsigned int term_screen_get_height(term_screen *screen) { - assert_return(screen, -EINVAL); - - return screen->page->height; -} - -uint64_t term_screen_get_age(term_screen *screen) { - assert_return(screen, 0); - - return screen->age; -} - -int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) { - uint32_t *ucs4_str; - size_t i, j, ucs4_len; - const term_seq *seq; - int r; - - assert_return(screen, -EINVAL); - - ++screen->age; - - /* Feed bytes into utf8 decoder and handle parsed ucs4 chars. We always - * treat data as UTF-8, but the parser makes sure to fall back to raw - * 8bit mode if the stream is not valid UTF-8. This should be more than - * enough to support old 7bit/8bit modes. */ - for (i = 0; i < size; ++i) { - ucs4_len = term_utf8_decode(&screen->utf8, &ucs4_str, in[i]); - for (j = 0; j < ucs4_len; ++j) { - r = term_parser_feed(screen->parser, &seq, ucs4_str[j]); - if (r < 0) { - return r; - } else if (r != TERM_SEQ_NONE) { - r = screen_feed_cmd(screen, seq); - if (r < 0) - return r; - } - } - } - - return 0; -} - -static char *screen_map_key(term_screen *screen, - char *p, - const uint32_t *keysyms, - size_t n_syms, - uint32_t ascii, - const uint32_t *ucs4, - unsigned int mods) { - char ch, ch2, ch_mods; - uint32_t v; - size_t i; - - /* TODO: All these key-mappings need to be verified. Public information - * on those mappings is pretty scarce and every emulator seems to do it - * slightly differently. - * A lot of mappings are also missing. */ - - if (n_syms < 1) - return p; - - if (n_syms == 1) - v = keysyms[0]; - else - v = XKB_KEY_NoSymbol; - - /* In some mappings, the modifiers are encoded as CSI parameters. The - * encoding is rather arbitrary, but seems to work. */ - ch_mods = 0; - switch (mods & (TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT | TERM_KBDMOD_CTRL)) { - case TERM_KBDMOD_SHIFT: - ch_mods = '2'; - break; - case TERM_KBDMOD_ALT: - ch_mods = '3'; - break; - case TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT: - ch_mods = '4'; - break; - case TERM_KBDMOD_CTRL: - ch_mods = '5'; - break; - case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT: - ch_mods = '6'; - break; - case TERM_KBDMOD_CTRL | TERM_KBDMOD_ALT: - ch_mods = '7'; - break; - case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT: - ch_mods = '8'; - break; - } - - /* A user might actually use multiple layouts for keyboard - * input. @keysyms[0] contains the actual keysym that the user - * used. But if this keysym is not in the ascii range, the - * input handler does check all other layouts that the user - * specified whether one of them maps the key to some ASCII - * keysym and provides this via @ascii. We always use the real - * keysym except when handling CTRL+<XY> shortcuts we use the - * ascii keysym. This is for compatibility to xterm et. al. so - * ctrl+c always works regardless of the currently active - * keyboard layout. But if no ascii-sym is found, we still use - * the real keysym. */ - if (ascii == XKB_KEY_NoSymbol) - ascii = v; - - /* map CTRL+<ascii> */ - if (mods & TERM_KBDMOD_CTRL) { - switch (ascii) { - case 0x60 ... 0x7e: - /* Right hand side is mapped to the left and then - * treated equally. Fall through to left-hand side.. */ - ascii -= 0x20; - case 0x20 ... 0x5f: - /* Printable ASCII is mapped 1-1 in XKB and in - * combination with CTRL bit 7 is flipped. This - * is equivalent to the caret-notation. */ - *p++ = ascii ^ 0x40; - return p; - } - } - - /* map cursor keys */ - ch = 0; - switch (v) { - case XKB_KEY_Up: - ch = 'A'; - break; - case XKB_KEY_Down: - ch = 'B'; - break; - case XKB_KEY_Right: - ch = 'C'; - break; - case XKB_KEY_Left: - ch = 'D'; - break; - case XKB_KEY_Home: - ch = 'H'; - break; - case XKB_KEY_End: - ch = 'F'; - break; - } - if (ch) { - *p++ = 0x1b; - if (screen->flags & TERM_FLAG_CURSOR_KEYS) - *p++ = 'O'; - else - *p++ = '['; - if (ch_mods) { - *p++ = '1'; - *p++ = ';'; - *p++ = ch_mods; - } - *p++ = ch; - return p; - } - - /* map action keys */ - ch = 0; - switch (v) { - case XKB_KEY_Find: - ch = '1'; - break; - case XKB_KEY_Insert: - ch = '2'; - break; - case XKB_KEY_Delete: - ch = '3'; - break; - case XKB_KEY_Select: - ch = '4'; - break; - case XKB_KEY_Page_Up: - ch = '5'; - break; - case XKB_KEY_Page_Down: - ch = '6'; - break; - } - if (ch) { - *p++ = 0x1b; - *p++ = '['; - *p++ = ch; - if (ch_mods) { - *p++ = ';'; - *p++ = ch_mods; - } - *p++ = '~'; - return p; - } - - /* map lower function keys */ - ch = 0; - switch (v) { - case XKB_KEY_F1: - ch = 'P'; - break; - case XKB_KEY_F2: - ch = 'Q'; - break; - case XKB_KEY_F3: - ch = 'R'; - break; - case XKB_KEY_F4: - ch = 'S'; - break; - } - if (ch) { - if (ch_mods) { - *p++ = 0x1b; - *p++ = '['; - *p++ = '1'; - *p++ = ';'; - *p++ = ch_mods; - *p++ = ch; - } else { - *p++ = 0x1b; - *p++ = 'O'; - *p++ = ch; - } - - return p; - } - - /* map upper function keys */ - ch = 0; - ch2 = 0; - switch (v) { - case XKB_KEY_F5: - ch = '1'; - ch2 = '5'; - break; - case XKB_KEY_F6: - ch = '1'; - ch2 = '7'; - break; - case XKB_KEY_F7: - ch = '1'; - ch2 = '8'; - break; - case XKB_KEY_F8: - ch = '1'; - ch2 = '9'; - break; - case XKB_KEY_F9: - ch = '2'; - ch2 = '0'; - break; - case XKB_KEY_F10: - ch = '2'; - ch2 = '1'; - break; - case XKB_KEY_F11: - ch = '2'; - ch2 = '2'; - break; - case XKB_KEY_F12: - ch = '2'; - ch2 = '3'; - break; - } - if (ch) { - *p++ = 0x1b; - *p++ = '['; - *p++ = ch; - if (ch2) - *p++ = ch2; - if (ch_mods) { - *p++ = ';'; - *p++ = ch_mods; - } - *p++ = '~'; - return p; - } - - /* map special keys */ - switch (v) { - case 0xff08: /* XKB_KEY_BackSpace */ - case 0xff09: /* XKB_KEY_Tab */ - case 0xff0a: /* XKB_KEY_Linefeed */ - case 0xff0b: /* XKB_KEY_Clear */ - case 0xff15: /* XKB_KEY_Sys_Req */ - case 0xff1b: /* XKB_KEY_Escape */ - case 0xffff: /* XKB_KEY_Delete */ - *p++ = v - 0xff00; - return p; - case 0xff13: /* XKB_KEY_Pause */ - /* TODO: What should we do with this key? - * Sending XOFF is awful as there is no simple - * way on modern keyboards to send XON again. - * If someone wants this, we can re-eanble - * optionally. */ - return p; - case 0xff14: /* XKB_KEY_Scroll_Lock */ - /* TODO: What should we do on scroll-lock? - * Sending 0x14 is what the specs say but it is - * not used today the way most users would - * expect so we disable it. If someone wants - * this, we can re-enable it (optionally). */ - return p; - case XKB_KEY_Return: - *p++ = 0x0d; - if (screen->flags & TERM_FLAG_NEWLINE_MODE) - *p++ = 0x0a; - return p; - case XKB_KEY_ISO_Left_Tab: - *p++ = 0x09; - return p; - } - - /* map unicode keys */ - for (i = 0; i < n_syms; ++i) - p += utf8_encode_unichar(p, ucs4[i]); - - return p; -} - -int term_screen_feed_keyboard(term_screen *screen, - const uint32_t *keysyms, - size_t n_syms, - uint32_t ascii, - const uint32_t *ucs4, - unsigned int mods) { - _cleanup_free_ char *dyn = NULL; - static const size_t padding = 1; - char buf[128], *start, *p; - - assert_return(screen, -EINVAL); - - /* allocate buffer if too small */ - start = buf; - if (4 * n_syms + padding > sizeof(buf)) { - dyn = malloc(4 * n_syms + padding); - if (!dyn) - return -ENOMEM; - - start = dyn; - } - - /* reserve prefix space */ - start += padding; - p = start; - - p = screen_map_key(screen, p, keysyms, n_syms, ascii, ucs4, mods); - if (!p || p - start < 1) - return 0; - - /* The ALT modifier causes ESC to be prepended to any key-stroke. We - * already accounted for that buffer space above, so simply prepend it - * here. - * TODO: is altSendsEscape a suitable default? What are the semantics - * exactly? Is it used in C0/C1 conversion? Is it prepended if there - * already is an escape character? */ - if (mods & TERM_KBDMOD_ALT && *start != 0x1b) - *--start = 0x1b; - - /* turn C0 into C1 */ - if (!(screen->flags & TERM_FLAG_7BIT_MODE) && p - start >= 2) - if (start[0] == 0x1b && start[1] >= 0x40 && start[1] <= 0x5f) - *++start ^= 0x40; - - return screen_write(screen, start, p - start); -} - -int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) { - unsigned int i; - uint8_t *t; - int r; - - assert_return(screen, -EINVAL); - - r = term_page_reserve(screen->page_main, x, y, &screen->state.attr, screen->age); - if (r < 0) - return r; - - r = term_page_reserve(screen->page_alt, x, y, &screen->state.attr, screen->age); - if (r < 0) - return r; - - if (x > screen->n_tabs) { - t = realloc(screen->tabs, (x + 7) / 8); - if (!t) - return -ENOMEM; - - screen->tabs = t; - screen->n_tabs = x; - } - - for (i = (screen->page->width + 7) / 8 * 8; i < x; i += 8) - screen->tabs[i / 8] = 0x1; - - term_page_resize(screen->page_main, x, y, &screen->state.attr, screen->age, screen->history); - term_page_resize(screen->page_alt, x, y, &screen->state.attr, screen->age, NULL); - - screen->state.cursor_x = screen_clamp_x(screen, screen->state.cursor_x); - screen->state.cursor_y = screen_clamp_x(screen, screen->state.cursor_y); - screen_cursor_clear_wrap(screen); - - return 0; -} - -void term_screen_soft_reset(term_screen *screen) { - unsigned int i; - - assert(screen); - - screen->g0 = &term_unicode_lower; - screen->g1 = &term_unicode_upper; - screen->g2 = &term_unicode_lower; - screen->g3 = &term_unicode_upper; - screen->state.attr = screen->default_attr; - screen->state.gl = &screen->g0; - screen->state.gr = &screen->g1; - screen->state.glt = NULL; - screen->state.grt = NULL; - screen->state.auto_wrap = 0; - screen->state.origin_mode = 0; - - screen->saved = screen->state; - screen->saved.cursor_x = 0; - screen->saved.cursor_y = 0; - screen->saved_alt = screen->saved; - - screen->page = screen->page_main; - screen->history = screen->history_main; - screen->flags = TERM_FLAG_7BIT_MODE; - screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400; - - for (i = 0; i < screen->page->width; i += 8) - screen->tabs[i / 8] = 0x1; - - term_page_set_scroll_region(screen->page_main, 0, screen->page->height); - term_page_set_scroll_region(screen->page_alt, 0, screen->page->height); -} - -void term_screen_hard_reset(term_screen *screen) { - assert(screen); - - term_screen_soft_reset(screen); - zero(screen->utf8); - screen->state.cursor_x = 0; - screen->state.cursor_y = 0; - term_page_erase(screen->page_main, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false); - term_page_erase(screen->page_alt, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false); -} - -int term_screen_set_answerback(term_screen *screen, const char *answerback) { - char *t = NULL; - - assert_return(screen, -EINVAL); - - if (answerback) { - t = strdup(answerback); - if (!t) - return -ENOMEM; - } - - free(screen->answerback); - screen->answerback = t; - - return 0; -} - -int term_screen_draw(term_screen *screen, - int (*draw_fn) (term_screen *screen, - void *userdata, - unsigned int x, - unsigned int y, - const term_attr *attr, - const uint32_t *ch, - size_t n_ch, - unsigned int ch_width), - void *userdata, - uint64_t *fb_age) { - uint64_t cell_age, line_age, age = 0; - term_charbuf_t ch_buf; - const uint32_t *ch_str; - unsigned int i, j, cw; - term_page *page; - term_line *line; - term_cell *cell; - size_t ch_n; - int r; - - assert(screen); - assert(draw_fn); - - if (fb_age) - age = *fb_age; - - page = screen->page; - - for (j = 0; j < page->height; ++j) { - line = page->lines[j]; - line_age = MAX(line->age, page->age); - - for (i = 0; i < page->width; ++i) { - term_attr attr; - - cell = &line->cells[i]; - cell_age = MAX(cell->age, line_age); - - if (age != 0 && cell_age <= age) - continue; - - ch_str = term_char_resolve(cell->ch, &ch_n, &ch_buf); - - /* Character-width of 0 is used for cleared cells. - * Always treat this as single-cell character, so - * renderers can assume ch_width is set properpy. */ - cw = MAX(cell->cwidth, 1U); - - attr = cell->attr; - if (i == screen->state.cursor_x && j == screen->state.cursor_y && - !(screen->flags & TERM_FLAG_HIDE_CURSOR)) - attr.inverse ^= 1; - - r = draw_fn(screen, - userdata, - i, - j, - &attr, - ch_str, - ch_n, - cw); - if (r != 0) - return r; - } - } - - if (fb_age) - *fb_age = screen->age; - - return 0; -} |