1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 * The term_screen layer implements the terminal-side. It handles all commands
25 * returned by the seq-parser and applies them to its own pages.
27 * While there are a lot of legacy control-sequences, we only support a small
28 * subset. There is no reason to implement unused codes like horizontal
30 * If you implement new commands, make sure to document them properly.
37 * http://www.vt100.net/emu/ctrlseq_dec.html
38 * http://www.vt100.net/docs/vt100-ug/chapter3.html
39 * http://www.vt100.net/docs/vt510-rm/chapter4
40 * http://www.vt100.net/docs/vt510-rm/contents
41 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
43 * http://en.wikipedia.org/wiki/C0_and_C1_control_codes
44 * https://en.wikipedia.org/wiki/ANSI_color
50 #include <xkbcommon/xkbcommon-keysyms.h>
52 #include "term-internal.h"
55 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) {
56 _cleanup_(term_screen_unrefp) term_screen *screen = NULL;
59 assert_return(out, -EINVAL);
61 screen = new0(term_screen, 1);
67 screen->write_fn = write_fn;
68 screen->write_fn_data = write_fn_data;
69 screen->cmd_fn = cmd_fn;
70 screen->cmd_fn_data = cmd_fn_data;
71 screen->flags = TERM_FLAG_7BIT_MODE;
72 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
73 screen->g0 = &term_unicode_lower;
74 screen->g1 = &term_unicode_upper;
75 screen->g2 = &term_unicode_lower;
76 screen->g3 = &term_unicode_upper;
77 screen->state.gl = &screen->g0;
78 screen->state.gr = &screen->g1;
79 screen->saved = screen->state;
81 r = term_page_new(&screen->page_main);
85 r = term_page_new(&screen->page_alt);
89 r = term_parser_new(&screen->parser, false);
93 r = term_history_new(&screen->history_main);
97 screen->page = screen->page_main;
98 screen->history = screen->history_main;
105 term_screen *term_screen_ref(term_screen *screen) {
109 assert_return(screen->ref > 0, NULL);
115 term_screen *term_screen_unref(term_screen *screen) {
119 assert_return(screen->ref > 0, NULL);
124 free(screen->answerback);
126 term_history_free(screen->history_main);
127 term_page_free(screen->page_alt);
128 term_page_free(screen->page_main);
129 term_parser_free(screen->parser);
137 * Unfortunately, 7bit/8bit compat mode requires us to send C1 controls encoded
138 * as 7bit if asked by the application. This is really used in the wild, so we
139 * cannot fall back to "always 7bit".
140 * screen_write() is the underlying backend which forwards any writes to the
141 * users's callback. It's the users responsibility to buffer these and write
142 * them out once their call to term_screen_feed_*() returns.
143 * The SEQ_WRITE() and SEQ_WRITE_KEY() macros allow constructing C0/C1 sequences
144 * directly in the code-base without requiring any intermediate buffer during
149 #define C1_CSI "\x9b"
151 #define SEQ(_screen, _prefix_esc, _c0, _c1, _seq) \
152 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
153 ((_prefix_esc) ? ("\e" _c0 _seq) : (_c0 _seq)) : \
154 ((_prefix_esc) ? ("\e" _c1 _seq) : (_c1 _seq)))
156 #define SEQ_SIZE(_screen, _prefix_esc, _c0, _c1, _seq) \
157 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
158 ((_prefix_esc) ? sizeof("\e" _c0 _seq) : sizeof(_c0 _seq)) : \
159 ((_prefix_esc) ? sizeof("\e" _c1 _seq) : sizeof(_c1 _seq)))
161 #define SEQ_WRITE_KEY(_screen, _prefix_esc, _c0, _c1, _seq) \
162 screen_write((_screen), \
163 SEQ((_screen), (_prefix_esc), \
165 SEQ_SIZE((_screen), (_prefix_esc), \
168 #define SEQ_WRITE(_screen, _c0, _c1, _seq) \
169 SEQ_WRITE_KEY((_screen), false, _c0, _c1, _seq)
171 static int screen_write(term_screen *screen, const void *buf, size_t len) {
172 if (len < 1 || !screen->write_fn)
175 return screen->write_fn(screen, screen->write_fn_data, buf, len);
180 * Some commands cannot be handled by the screen-layer directly. Those are
181 * forwarded to the command-handler of the caller. This is rarely used and can
182 * safely be set to NULL.
185 static int screen_forward(term_screen *screen, unsigned int cmd, const term_seq *seq) {
189 return screen->cmd_fn(screen, screen->cmd_fn_data, cmd, seq);
194 * These helpers implement common-operations like cursor-handler and more, which
195 * are used by several command dispatchers.
198 static unsigned int screen_clamp_x(term_screen *screen, unsigned int x) {
199 if (x >= screen->page->width)
200 return (screen->page->width > 0) ? screen->page->width - 1 : 0;
205 static unsigned int screen_clamp_y(term_screen *screen, unsigned int y) {
206 if (y >= screen->page->height)
207 return (screen->page->height > 0) ? screen->page->height - 1 : 0;
212 static bool screen_tab_is_set(term_screen *screen, unsigned int pos) {
213 if (pos >= screen->page->width)
216 return screen->tabs[pos / 8] & (1 << (pos % 8));
219 static inline void screen_age_cursor(term_screen *screen) {
222 cell = term_page_get_cell(screen->page, screen->state.cursor_x, screen->state.cursor_y);
224 cell->age = screen->age;
227 static void screen_cursor_clear_wrap(term_screen *screen) {
228 screen->flags &= ~TERM_FLAG_PENDING_WRAP;
231 static void screen_cursor_set(term_screen *screen, unsigned int x, unsigned int y) {
232 x = screen_clamp_x(screen, x);
233 y = screen_clamp_y(screen, y);
235 if (x == screen->state.cursor_x && y == screen->state.cursor_y)
238 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
239 screen_age_cursor(screen);
241 screen->state.cursor_x = x;
242 screen->state.cursor_y = y;
244 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
245 screen_age_cursor(screen);
248 static void screen_cursor_set_rel(term_screen *screen, unsigned int x, unsigned int y) {
249 if (screen->state.origin_mode) {
250 x = screen_clamp_x(screen, x);
251 y = screen_clamp_x(screen, y) + screen->page->scroll_idx;
253 if (y >= screen->page->scroll_idx + screen->page->scroll_num) {
254 y = screen->page->scroll_idx + screen->page->scroll_num;
255 if (screen->page->scroll_num > 0)
260 screen_cursor_set(screen, x, y);
263 static void screen_cursor_left(term_screen *screen, unsigned int num) {
264 if (num > screen->state.cursor_x)
265 num = screen->state.cursor_x;
267 screen_cursor_set(screen, screen->state.cursor_x - num, screen->state.cursor_y);
270 static void screen_cursor_left_tab(term_screen *screen, unsigned int num) {
273 i = screen->state.cursor_x;
274 while (i > 0 && num > 0) {
275 if (screen_tab_is_set(screen, --i))
279 screen_cursor_set(screen, i, screen->state.cursor_y);
282 static void screen_cursor_right(term_screen *screen, unsigned int num) {
283 if (num > screen->page->width)
284 num = screen->page->width;
286 screen_cursor_set(screen, screen->state.cursor_x + num, screen->state.cursor_y);
289 static void screen_cursor_right_tab(term_screen *screen, unsigned int num) {
292 i = screen->state.cursor_x;
293 while (i + 1 < screen->page->width && num > 0) {
294 if (screen_tab_is_set(screen, ++i))
298 screen_cursor_set(screen, i, screen->state.cursor_y);
301 static void screen_cursor_up(term_screen *screen, unsigned int num, bool scroll) {
304 if (screen->state.cursor_y < screen->page->scroll_idx) {
305 if (num > screen->state.cursor_y)
306 num = screen->state.cursor_y;
308 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
310 max = screen->state.cursor_y - screen->page->scroll_idx;
315 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
316 screen_age_cursor(screen);
319 term_page_scroll_down(screen->page, num - max, &screen->state.attr, screen->age, NULL);
321 screen->state.cursor_y = screen->page->scroll_idx;
323 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
324 screen_age_cursor(screen);
326 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
331 static void screen_cursor_down(term_screen *screen, unsigned int num, bool scroll) {
334 if (screen->state.cursor_y >= screen->page->scroll_idx + screen->page->scroll_num) {
335 if (num > screen->page->height)
336 num = screen->page->height;
338 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
340 max = screen->page->scroll_idx + screen->page->scroll_num - 1 - screen->state.cursor_y;
345 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
346 screen_age_cursor(screen);
349 term_page_scroll_up(screen->page, num - max, &screen->state.attr, screen->age, screen->history);
351 screen->state.cursor_y = screen->page->scroll_idx + screen->page->scroll_num - 1;
353 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
354 screen_age_cursor(screen);
356 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y + num);
361 static void screen_save_state(term_screen *screen, term_state *where) {
362 *where = screen->state;
365 static void screen_restore_state(term_screen *screen, term_state *from) {
366 screen_cursor_set(screen, from->cursor_x, from->cursor_y);
367 screen->state = *from;
370 static inline void set_reset(term_screen *screen, unsigned int flag, bool set) {
372 screen->flags |= flag;
374 screen->flags &= ~flag;
377 static void screen_mode_change(term_screen *screen, unsigned int mode, bool dec, bool set) {
382 * DECCKM: cursor-keys
385 set_reset(screen, TERM_FLAG_CURSOR_KEYS, set);
395 screen->state.origin_mode = set;
402 * DECAWN: auto-wrap mode
405 screen->state.auto_wrap = set;
412 * LNM: line-feed/new-line mode
415 set_reset(screen, TERM_FLAG_NEWLINE_MODE, set);
422 * DECTCEM: text-cursor-enable
425 set_reset(screen, TERM_FLAG_HIDE_CURSOR, !set);
426 screen_age_cursor(screen);
433 /* map a character according to current GL and GR maps */
434 static uint32_t screen_map(term_screen *screen, uint32_t val) {
437 /* 32 and 127 always map to identity. 160 and 255 map to identity iff a
438 * 96 character set is loaded into GR. Values above 255 always map to
442 if (screen->state.glt) {
443 nval = (**screen->state.glt)[val - 32];
444 screen->state.glt = NULL;
446 nval = (**screen->state.gl)[val - 32];
450 if (screen->state.grt) {
451 nval = (**screen->state.grt)[val - 160];
452 screen->state.grt = NULL;
454 nval = (**screen->state.gr)[val - 160];
459 return (nval == -1U) ? val : nval;
464 * This is the unofficial documentation of all the TERM_CMD_* definitions. Each
465 * handled command has a separate function with an extensive comment on the
466 * semantics of the command.
467 * Note that many semantics are unknown and need to be verified. This is mostly
468 * about error-handling, though. Applications rarely rely on those features.
471 static int screen_DA1(term_screen *screen, const term_seq *seq);
472 static int screen_LF(term_screen *screen, const term_seq *seq);
474 static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) {
475 term_char_t ch = TERM_CHAR_NULL;
478 if (screen->state.cursor_x + 1 == screen->page->width
479 && screen->flags & TERM_FLAG_PENDING_WRAP
480 && screen->state.auto_wrap) {
481 screen_cursor_down(screen, 1, true);
482 screen_cursor_set(screen, 0, screen->state.cursor_y);
485 screen_cursor_clear_wrap(screen);
487 c = screen_map(screen, seq->terminator);
488 ch = term_char_merge(ch, screen_map(screen, c));
489 term_page_write(screen->page, screen->state.cursor_x, screen->state.cursor_y, ch, 1, &screen->state.attr, screen->age, false);
491 if (screen->state.cursor_x + 1 == screen->page->width)
492 screen->flags |= TERM_FLAG_PENDING_WRAP;
494 screen_cursor_right(screen, 1);
499 static int screen_BEL(term_screen *screen, const term_seq *seq) {
501 * BEL - sound bell tone
502 * This command should trigger an acoustic bell. Usually, this is
503 * forwarded directly to the pcspkr. However, bells have become quite
504 * uncommon and annoying, so we're not implementing them here. Instead,
505 * it's one of the commands we forward to the caller.
508 return screen_forward(screen, TERM_CMD_BEL, seq);
511 static int screen_BS(term_screen *screen, const term_seq *seq) {
514 * Move cursor one cell to the left. If already at the left margin,
518 screen_cursor_clear_wrap(screen);
519 screen_cursor_left(screen, 1);
523 static int screen_CBT(term_screen *screen, const term_seq *seq) {
525 * CBT - cursor-backward-tabulation
526 * Move the cursor @args[0] tabs backwards (to the left). The
527 * current cursor cell, in case it's a tab, is not counted.
528 * Furthermore, the cursor cannot be moved beyond position 0 and
529 * it will stop there.
535 unsigned int num = 1;
537 if (seq->args[0] > 0)
540 screen_cursor_clear_wrap(screen);
541 screen_cursor_left_tab(screen, num);
546 static int screen_CHA(term_screen *screen, const term_seq *seq) {
548 * CHA - cursor-horizontal-absolute
549 * Move the cursor to position @args[0] in the current line. The
550 * cursor cannot be moved beyond the rightmost cell and will stop
557 unsigned int pos = 1;
559 if (seq->args[0] > 0)
562 screen_cursor_clear_wrap(screen);
563 screen_cursor_set(screen, pos - 1, screen->state.cursor_y);
568 static int screen_CHT(term_screen *screen, const term_seq *seq) {
570 * CHT - cursor-horizontal-forward-tabulation
571 * Move the cursor @args[0] tabs forward (to the right). The
572 * current cursor cell, in case it's a tab, is not counted.
573 * Furthermore, the cursor cannot be moved beyond the rightmost cell
574 * and will stop there.
580 unsigned int num = 1;
582 if (seq->args[0] > 0)
585 screen_cursor_clear_wrap(screen);
586 screen_cursor_right_tab(screen, num);
591 static int screen_CNL(term_screen *screen, const term_seq *seq) {
593 * CNL - cursor-next-line
594 * Move the cursor @args[0] lines down.
596 * TODO: Does this stop at the bottom or cause a scroll-up?
602 unsigned int num = 1;
604 if (seq->args[0] > 0)
607 screen_cursor_clear_wrap(screen);
608 screen_cursor_down(screen, num, false);
613 static int screen_CPL(term_screen *screen, const term_seq *seq) {
615 * CPL - cursor-preceding-line
616 * Move the cursor @args[0] lines up.
618 * TODO: Does this stop at the top or cause a scroll-up?
624 unsigned int num = 1;
626 if (seq->args[0] > 0)
629 screen_cursor_clear_wrap(screen);
630 screen_cursor_up(screen, num, false);
635 static int screen_CR(term_screen *screen, const term_seq *seq) {
637 * CR - carriage-return
638 * Move the cursor to the left margin on the current line.
641 screen_cursor_clear_wrap(screen);
642 screen_cursor_set(screen, 0, screen->state.cursor_y);
647 static int screen_CUB(term_screen *screen, const term_seq *seq) {
649 * CUB - cursor-backward
650 * Move the cursor @args[0] positions to the left. The cursor stops
651 * at the left-most position.
657 unsigned int num = 1;
659 if (seq->args[0] > 0)
662 screen_cursor_clear_wrap(screen);
663 screen_cursor_left(screen, num);
668 static int screen_CUD(term_screen *screen, const term_seq *seq) {
671 * Move the cursor @args[0] positions down. The cursor stops at the
672 * bottom margin. If it was already moved further, it stops at the
679 unsigned int num = 1;
681 if (seq->args[0] > 0)
684 screen_cursor_clear_wrap(screen);
685 screen_cursor_down(screen, num, false);
690 static int screen_CUF(term_screen *screen, const term_seq *seq) {
692 * CUF -cursor-forward
693 * Move the cursor @args[0] positions to the right. The cursor stops
694 * at the right-most position.
700 unsigned int num = 1;
702 if (seq->args[0] > 0)
705 screen_cursor_clear_wrap(screen);
706 screen_cursor_right(screen, num);
711 static int screen_CUP(term_screen *screen, const term_seq *seq) {
713 * CUP - cursor-position
714 * Moves the cursor to position @args[1] x @args[0]. If either is 0, it
715 * is treated as 1. The positions are subject to the origin-mode and
716 * clamped to the addressable with/height.
723 unsigned int x = 1, y = 1;
725 if (seq->args[0] > 0)
727 if (seq->args[1] > 0)
730 screen_cursor_clear_wrap(screen);
731 screen_cursor_set_rel(screen, x - 1, y - 1);
736 static int screen_CUU(term_screen *screen, const term_seq *seq) {
739 * Move the cursor @args[0] positions up. The cursor stops at the
740 * top margin. If it was already moved further, it stops at the
748 unsigned int num = 1;
750 if (seq->args[0] > 0)
753 screen_cursor_clear_wrap(screen);
754 screen_cursor_up(screen, num, false);
759 static int screen_DA1(term_screen *screen, const term_seq *seq) {
761 * DA1 - primary-device-attributes
762 * The primary DA asks for basic terminal features. We simply return
763 * a hard-coded list of features we implement.
764 * Note that the primary DA asks for supported features, not currently
767 * The terminal's answer is:
769 * The first argument, 64, is fixed and denotes a VT420, the last
770 * DEC-term that extended this number.
771 * All following arguments denote supported features. Note
772 * that at most 15 features can be sent (max CSI args). It is safe to
773 * send more, but clients might not be able to parse them. This is a
774 * client's problem and we shouldn't care. There is no other way to
775 * send those feature lists, so we have to extend them beyond 15 in
780 * The 132 column mode is supported by the terminal.
782 * A priner-port is supported and can be addressed via
785 * Support for ReGIS graphics is available. The ReGIS routines
786 * provide the "remote graphics instruction set" and allow basic
789 * Support of Sixel graphics is available. This provides access
790 * to the sixel bitmap routines.
792 * The terminal supports DECSCA and related selective-erase
793 * functions. This allows to protect specific cells from being
794 * erased, if specified.
795 * 7: soft character set (DRCS)
797 * 8: user-defined keys (UDKs)
799 * 9: national-replacement character sets (NRCS)
800 * National-replacement character-sets are available.
801 * 12: Yugoslavian (SCS)
803 * 15: technical character set
804 * The DEC technical-character-set is available.
805 * 18: windowing capability
807 * 21: horizontal scrolling
815 * 29: ANSI text locator
817 * 42: ISO Latin-2 character set
823 * 46: ASCII emulation
827 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "?64;1;6;9;15c");
830 static int screen_DA2(term_screen *screen, const term_seq *seq) {
832 * DA2 - secondary-device-attributes
833 * The secondary DA asks for the terminal-ID, firmware versions and
834 * other non-primary attributes. All these values are
835 * informational-only and should not be used by the host to detect
838 * The terminal's response is:
839 * ^[ > 61 ; FIRMWARE ; KEYBOARD c
840 * whereas 65 is fixed for VT525 terminals, the last terminal-line that
841 * increased this number. FIRMWARE is the firmware
842 * version encoded as major/minor (20 == 2.0) and KEYBOARD is 0 for STD
843 * keyboard and 1 for PC keyboards.
845 * We replace the firmware-version with the systemd-version so clients
846 * can decode it again.
849 return SEQ_WRITE(screen, C0_CSI, C1_CSI, ">65;" PACKAGE_VERSION ";1c");
852 static int screen_DA3(term_screen *screen, const term_seq *seq) {
854 * DA3 - tertiary-device-attributes
855 * The tertiary DA is used to query the terminal-ID.
857 * The terminal's response is:
858 * ^P ! | XX AA BB CC ^\
859 * whereas all four parameters are hexadecimal-encoded pairs. XX
860 * denotes the manufacturing site, AA BB CC is the terminal's ID.
863 /* we do not support tertiary DAs */
867 static int screen_DC1(term_screen *screen, const term_seq *seq) {
869 * DC1 - device-control-1 or XON
870 * This clears any previous XOFF and resumes terminal-transmission.
873 /* we do not support XON */
877 static int screen_DC3(term_screen *screen, const term_seq *seq) {
879 * DC3 - device-control-3 or XOFF
880 * Stops terminal transmission. No further characters are sent until
881 * an XON is received.
884 /* we do not support XOFF */
888 static int screen_DCH(term_screen *screen, const term_seq *seq) {
890 * DCH - delete-character
891 * This deletes @argv[0] characters at the current cursor position. As
892 * characters are deleted, the remaining characters between the cursor
893 * and right margin move to the left. Character attributes move with the
894 * characters. The terminal adds blank spaces with no visual character
895 * attributes at the right margin. DCH has no effect outside the
902 unsigned int num = 1;
904 if (seq->args[0] > 0)
907 screen_cursor_clear_wrap(screen);
908 term_page_delete_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age);
913 static int screen_DECALN(term_screen *screen, const term_seq *seq) {
915 * DECALN - screen-alignment-pattern
917 * Probably not worth implementing.
923 static int screen_DECANM(term_screen *screen, const term_seq *seq) {
926 * Set the terminal into VT52 compatibility mode. Control sequences
927 * overlap with regular sequences so we have to detect them early before
930 * Probably not worth implementing.
936 static int screen_DECBI(term_screen *screen, const term_seq *seq) {
939 * This control function moves the cursor backward one column. If the
940 * cursor is at the left margin, then all screen data within the margin
941 * moves one column to the right. The column that shifted past the right
943 * DECBI adds a new column at the left margin with no visual attributes.
944 * DECBI does not affect the margins. If the cursor is beyond the
945 * left-margin at the left border, then the terminal ignores DECBI.
947 * Probably not worth implementing.
953 static int screen_DECCARA(term_screen *screen, const term_seq *seq) {
955 * DECCARA - change-attributes-in-rectangular-area
957 * Probably not worth implementing.
963 static int screen_DECCRA(term_screen *screen, const term_seq *seq) {
965 * DECCRA - copy-rectangular-area
967 * Probably not worth implementing.
973 static int screen_DECDC(term_screen *screen, const term_seq *seq) {
975 * DECDC - delete-column
977 * Probably not worth implementing.
983 static int screen_DECDHL_BH(term_screen *screen, const term_seq *seq) {
985 * DECDHL_BH - double-width-double-height-line: bottom half
987 * Probably not worth implementing.
993 static int screen_DECDHL_TH(term_screen *screen, const term_seq *seq) {
995 * DECDHL_TH - double-width-double-height-line: top half
997 * Probably not worth implementing.
1003 static int screen_DECDWL(term_screen *screen, const term_seq *seq) {
1005 * DECDWL - double-width-single-height-line
1007 * Probably not worth implementing.
1013 static int screen_DECEFR(term_screen *screen, const term_seq *seq) {
1015 * DECEFR - enable-filter-rectangle
1016 * Defines the coordinates of a filter rectangle (top, left, bottom,
1017 * right as @args[0] to @args[3]) and activates it.
1018 * Anytime the locator is detected outside of the filter rectangle, an
1019 * outside rectangle event is generated and the rectangle is disabled.
1020 * Filter rectangles are always treated as "one-shot" events. Any
1021 * parameters that are omitted default to the current locator position.
1022 * If all parameters are omitted, any locator motion will be reported.
1023 * DECELR always cancels any prevous rectangle definition.
1025 * The locator is usually associated with the mouse-cursor, but based
1026 * on cells instead of pixels. See DECELR how to initialize and enable
1027 * it. DECELR can also enable pixel-mode instead of cell-mode.
1035 static int screen_DECELF(term_screen *screen, const term_seq *seq) {
1037 * DECELF - enable-local-functions
1039 * Probably not worth implementing.
1045 static int screen_DECELR(term_screen *screen, const term_seq *seq) {
1047 * DECELR - enable-locator-reporting
1048 * This changes the locator-reporting mode. @args[0] specifies the mode
1049 * to set, 0 disables locator-reporting, 1 enables it continuously, 2
1050 * enables it for a single report. @args[1] specifies the
1051 * precision-mode. 0 and 2 set the reporting to cell-precision, 1 sets
1064 static int screen_DECERA(term_screen *screen, const term_seq *seq) {
1066 * DECERA - erase-rectangular-area
1068 * Probably not worth implementing.
1074 static int screen_DECFI(term_screen *screen, const term_seq *seq) {
1076 * DECFI - forward-index
1077 * This control function moves the cursor forward one column. If the
1078 * cursor is at the right margin, then all screen data within the
1079 * margins moves one column to the left. The column shifted past the
1080 * left margin is lost.
1081 * DECFI adds a new column at the right margin, with no visual
1082 * attributes. DECFI does not affect margins. If the cursor is beyond
1083 * the right margin at the border of the page when the terminal
1084 * receives DECFI, then the terminal ignores DECFI.
1086 * Probably not worth implementing.
1092 static int screen_DECFRA(term_screen *screen, const term_seq *seq) {
1094 * DECFRA - fill-rectangular-area
1096 * Probably not worth implementing.
1102 static int screen_DECIC(term_screen *screen, const term_seq *seq) {
1104 * DECIC - insert-column
1106 * Probably not worth implementing.
1112 static int screen_DECID(term_screen *screen, const term_seq *seq) {
1114 * DECID - return-terminal-id
1115 * This is an obsolete form of TERM_CMD_DA1.
1118 return screen_DA1(screen, seq);
1121 static int screen_DECINVM(term_screen *screen, const term_seq *seq) {
1123 * DECINVM - invoke-macro
1125 * Probably not worth implementing.
1131 static int screen_DECKBD(term_screen *screen, const term_seq *seq) {
1133 * DECKBD - keyboard-language-selection
1135 * Probably not worth implementing.
1141 static int screen_DECKPAM(term_screen *screen, const term_seq *seq) {
1143 * DECKPAM - keypad-application-mode
1144 * Enables the keypad-application mode. If enabled, the keypad sends
1145 * special characters instead of the printed characters. This way,
1146 * applications can detect whether a numeric key was pressed on the
1147 * top-row or on the keypad.
1148 * Default is keypad-numeric-mode.
1151 screen->flags |= TERM_FLAG_KEYPAD_MODE;
1156 static int screen_DECKPNM(term_screen *screen, const term_seq *seq) {
1158 * DECKPNM - keypad-numeric-mode
1159 * This disables the keypad-application-mode (DECKPAM) and returns to
1160 * the keypad-numeric-mode. Keypresses on the keypad generate the same
1161 * sequences as corresponding keypresses on the main keyboard.
1162 * Default is keypad-numeric-mode.
1165 screen->flags &= ~TERM_FLAG_KEYPAD_MODE;
1170 static int screen_DECLFKC(term_screen *screen, const term_seq *seq) {
1172 * DECLFKC - local-function-key-control
1174 * Probably not worth implementing.
1180 static int screen_DECLL(term_screen *screen, const term_seq *seq) {
1184 * Probably not worth implementing.
1190 static int screen_DECLTOD(term_screen *screen, const term_seq *seq) {
1192 * DECLTOD - load-time-of-day
1194 * Probably not worth implementing.
1200 static int screen_DECPCTERM(term_screen *screen, const term_seq *seq) {
1202 * DECPCTERM - pcterm-mode
1203 * This enters/exits the PCTerm mode. Default mode is VT-mode. It can
1204 * also select parameters for scancode/keycode mappings in SCO mode.
1206 * Definitely not worth implementing. Lets kill PCTerm/SCO modes!
1212 static int screen_DECPKA(term_screen *screen, const term_seq *seq) {
1214 * DECPKA - program-key-action
1216 * Probably not worth implementing.
1222 static int screen_DECPKFMR(term_screen *screen, const term_seq *seq) {
1224 * DECPKFMR - program-key-free-memory-report
1226 * Probably not worth implementing.
1232 static int screen_DECRARA(term_screen *screen, const term_seq *seq) {
1234 * DECRARA - reverse-attributes-in-rectangular-area
1236 * Probably not worth implementing.
1242 static int screen_DECRC(term_screen *screen, const term_seq *seq) {
1244 * DECRC - restore-cursor
1245 * Restores the terminal to the state saved by the save cursor (DECSC)
1246 * function. This includes more than just the cursor-position.
1248 * If nothing was saved by DECSC, then DECRC performs the following
1250 * * Moves the cursor to the home position (upper left of screen).
1251 * * Resets origin mode (DECOM).
1252 * * Turns all character attributes off (normal setting).
1253 * * Maps the ASCII character set into GL, and the DEC Supplemental
1254 * Graphic set into GR.
1256 * The terminal maintains a separate DECSC buffer for the main display
1257 * and the status line. This feature lets you save a separate operating
1258 * state for the main display and the status line.
1261 screen_restore_state(screen, &screen->saved);
1266 static int screen_DECREQTPARM(term_screen *screen, const term_seq *seq) {
1268 * DECREQTPARM - request-terminal-parameters
1269 * The sequence DECREPTPARM is sent by the terminal controller to notify
1270 * the host of the status of selected terminal parameters. The status
1271 * sequence may be sent when requested by the host or at the terminal's
1272 * discretion. DECREPTPARM is sent upon receipt of a DECREQTPARM.
1274 * If @args[0] is 0, this marks a request and the terminal is allowed
1275 * to send DECREPTPARM messages without request. If it is 1, the same
1276 * applies but the terminal should no longer send DECREPTPARM
1278 * 2 and 3 mark a report, but 3 is only used if the terminal answers as
1279 * an explicit request with @args[0] == 1.
1281 * The other arguments are ignored in requests, but have the following
1282 * meaning in responses:
1283 * args[1]: 1=no-parity-set 4=parity-set-and-odd 5=parity-set-and-even
1284 * args[2]: 1=8bits-per-char 2=7bits-per-char
1285 * args[3]: transmission-speed
1286 * args[4]: receive-speed
1287 * args[5]: 1=bit-rate-multiplier-is-16
1288 * args[6]: This value communicates the four switch values in block 5
1289 * of SETUP B, which are only visible to the user when an STP
1290 * option is installed. These bits may be assigned for an STP
1291 * device. The four bits are a decimal-encoded binary number.
1292 * Value between 0-15.
1294 * The transmission/receive speeds have mappings for number => bits/s
1295 * which are quite weird. Examples are: 96->3600, 112->9600, 120->19200
1301 if (seq->n_args < 1 || seq->args[0] == 0) {
1302 screen->flags &= ~TERM_FLAG_INHIBIT_TPARM;
1303 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "2;1;1;120;120;1;0x");
1304 } else if (seq->args[0] == 1) {
1305 screen->flags |= TERM_FLAG_INHIBIT_TPARM;
1306 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "3;1;1;120;120;1;0x");
1312 static int screen_DECRPKT(term_screen *screen, const term_seq *seq) {
1314 * DECRPKT - report-key-type
1315 * Response to DECRQKT, we can safely ignore it as we're the one sending
1322 static int screen_DECRQCRA(term_screen *screen, const term_seq *seq) {
1324 * DECRQCRA - request-checksum-of-rectangular-area
1326 * Probably not worth implementing.
1332 static int screen_DECRQDE(term_screen *screen, const term_seq *seq) {
1334 * DECRQDE - request-display-extent
1336 * Probably not worth implementing.
1342 static int screen_DECRQKT(term_screen *screen, const term_seq *seq) {
1344 * DECRQKT - request-key-type
1346 * Probably not worth implementing.
1352 static int screen_DECRQLP(term_screen *screen, const term_seq *seq) {
1354 * DECRQLP - request-locator-position
1355 * See DECELR for locator-information.
1357 * TODO: document and implement
1363 static int screen_DECRQM_ANSI(term_screen *screen, const term_seq *seq) {
1365 * DECRQM_ANSI - request-mode-ansi
1366 * The host sends this control function to find out if a particular mode
1367 * is set or reset. The terminal responds with a report mode function.
1368 * @args[0] contains the mode to query.
1370 * Response is DECRPM with the first argument set to the mode that was
1371 * queried, second argument is 0 if mode is invalid, 1 if mode is set,
1372 * 2 if mode is not set (reset), 3 if mode is permanently set and 4 if
1373 * mode is permanently not set (reset):
1374 * ANSI: ^[ MODE ; VALUE $ y
1375 * DEC: ^[ ? MODE ; VALUE $ y
1383 static int screen_DECRQM_DEC(term_screen *screen, const term_seq *seq) {
1385 * DECRQM_DEC - request-mode-dec
1386 * Same as DECRQM_ANSI but for DEC modes.
1394 static int screen_DECRQPKFM(term_screen *screen, const term_seq *seq) {
1396 * DECRQPKFM - request-program-key-free-memory
1398 * Probably not worth implementing.
1404 static int screen_DECRQPSR(term_screen *screen, const term_seq *seq) {
1406 * DECRQPSR - request-presentation-state-report
1408 * Probably not worth implementing.
1414 static int screen_DECRQTSR(term_screen *screen, const term_seq *seq) {
1416 * DECRQTSR - request-terminal-state-report
1418 * Probably not worth implementing.
1424 static int screen_DECRQUPSS(term_screen *screen, const term_seq *seq) {
1426 * DECRQUPSS - request-user-preferred-supplemental-set
1428 * Probably not worth implementing.
1434 static int screen_DECSACE(term_screen *screen, const term_seq *seq) {
1436 * DECSACE - select-attribute-change-extent
1438 * Probably not worth implementing.
1444 static int screen_DECSASD(term_screen *screen, const term_seq *seq) {
1446 * DECSASD - select-active-status-display
1448 * Probably not worth implementing.
1454 static int screen_DECSC(term_screen *screen, const term_seq *seq) {
1456 * DECSC - save-cursor
1457 * Save cursor and terminal state so it can be restored later on.
1458 * Saves the following items in the terminal's memory:
1460 * * Character attributes set by the SGR command
1461 * * Character sets (G0, G1, G2, or G3) currently in GL and GR
1462 * * Wrap flag (autowrap or no autowrap)
1463 * * State of origin mode (DECOM)
1464 * * Selective erase attribute
1465 * * Any single shift 2 (SS2) or single shift 3 (SS3) functions sent
1468 screen_save_state(screen, &screen->saved);
1473 static int screen_DECSCA(term_screen *screen, const term_seq *seq) {
1475 * DECSCA - select-character-protection-attribute
1476 * Defines the characters that come after it as erasable or not erasable
1477 * from the screen. The selective erase control functions (DECSED and
1478 * DECSEL) can only erase characters defined as erasable.
1480 * @args[0] specifies the new mode. 0 and 2 mark any following character
1481 * as erasable, 1 marks it as not erasable.
1487 unsigned int mode = 0;
1489 if (seq->args[0] > 0)
1490 mode = seq->args[0];
1495 screen->state.attr.protect = 0;
1498 screen->state.attr.protect = 1;
1505 static int screen_DECSCL(term_screen *screen, const term_seq *seq) {
1507 * DECSCL - select-conformance-level
1508 * Select the terminal's operating level. The factory default is
1509 * level 4 (VT Level 4 mode, 7-bit controls).
1510 * When you change the conformance level, the terminal performs a hard
1513 * @args[0] defines the conformance-level, valid values are:
1514 * 61: Level 1 (VT100)
1515 * 62: Level 2 (VT200)
1516 * 63: Level 3 (VT300)
1517 * 64: Level 4 (VT400)
1518 * @args[1] defines the 8bit-mode, valid values are:
1521 * 2: 8-bit controls (same as 0)
1523 * If @args[0] is 61, then @args[1] is ignored and 7bit controls are
1531 unsigned int level = 64, bit = 0;
1533 if (seq->n_args > 0) {
1534 level = seq->args[0];
1535 if (seq->n_args > 1)
1539 term_screen_hard_reset(screen);
1543 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT100;
1544 screen->flags |= TERM_FLAG_7BIT_MODE;
1547 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
1549 screen->flags |= TERM_FLAG_7BIT_MODE;
1551 screen->flags &= ~TERM_FLAG_7BIT_MODE;
1558 static int screen_DECSCP(term_screen *screen, const term_seq *seq) {
1560 * DECSCP - select-communication-port
1562 * Probably not worth implementing.
1568 static int screen_DECSCPP(term_screen *screen, const term_seq *seq) {
1570 * DECSCPP - select-columns-per-page
1571 * Select columns per page. The number of rows is unaffected by this.
1572 * @args[0] selectes the number of columns (width), DEC only defines 80
1573 * and 132, but we allow any integer here. 0 is equivalent to 80.
1574 * Page content is *not* cleared and the cursor is left untouched.
1575 * However, if the page is reduced in width and the cursor would be
1576 * outside the visible region, it's set to the right border. Newly added
1577 * cells are cleared. No data is retained outside the visible region.
1588 static int screen_DECSCS(term_screen *screen, const term_seq *seq) {
1590 * DECSCS - select-communication-speed
1592 * Probably not worth implementing.
1598 static int screen_DECSCUSR(term_screen *screen, const term_seq *seq) {
1600 * DECSCUSR - set-cursor-style
1601 * This changes the style of the cursor. @args[0] can be one of:
1602 * 0, 1: blinking block
1604 * 3: blinking underline
1605 * 4: steady underline
1606 * Changing this setting does _not_ affect the cursor visibility itself.
1607 * Use DECTCEM for that.
1618 static int screen_DECSDDT(term_screen *screen, const term_seq *seq) {
1620 * DECSDDT - select-disconnect-delay-time
1622 * Probably not worth implementing.
1628 static int screen_DECSDPT(term_screen *screen, const term_seq *seq) {
1630 * DECSDPT - select-digital-printed-data-type
1632 * Probably not worth implementing.
1638 static int screen_DECSED(term_screen *screen, const term_seq *seq) {
1640 * DECSED - selective-erase-in-display
1641 * This control function erases some or all of the erasable characters
1642 * in the display. DECSED can only erase characters defined as erasable
1643 * by the DECSCA control function. DECSED works inside or outside the
1644 * scrolling margins.
1646 * @args[0] defines which regions are erased. If it is 0, all cells from
1647 * the cursor (inclusive) till the end of the display are erase. If it
1648 * is 1, all cells from the start of the display till the cursor
1649 * (inclusive) are erased. If it is 2, all cells are erased.
1655 unsigned int mode = 0;
1657 if (seq->args[0] > 0)
1658 mode = seq->args[0];
1662 term_page_erase(screen->page,
1663 screen->state.cursor_x, screen->state.cursor_y,
1664 screen->page->width, screen->page->height,
1665 &screen->state.attr, screen->age, true);
1668 term_page_erase(screen->page,
1670 screen->state.cursor_x, screen->state.cursor_y,
1671 &screen->state.attr, screen->age, true);
1674 term_page_erase(screen->page,
1676 screen->page->width, screen->page->height,
1677 &screen->state.attr, screen->age, true);
1684 static int screen_DECSEL(term_screen *screen, const term_seq *seq) {
1686 * DECSEL - selective-erase-in-line
1687 * This control function erases some or all of the erasable characters
1688 * in a single line of text. DECSEL erases only those characters defined
1689 * as erasable by the DECSCA control function. DECSEL works inside or
1690 * outside the scrolling margins.
1692 * @args[0] defines the region to be erased. If it is 0, all cells from
1693 * the cursor (inclusive) till the end of the line are erase. If it is
1694 * 1, all cells from the start of the line till the cursor (inclusive)
1695 * are erased. If it is 2, the whole line of the cursor is erased.
1701 unsigned int mode = 0;
1703 if (seq->args[0] > 0)
1704 mode = seq->args[0];
1708 term_page_erase(screen->page,
1709 screen->state.cursor_x, screen->state.cursor_y,
1710 screen->page->width, screen->state.cursor_y,
1711 &screen->state.attr, screen->age, true);
1714 term_page_erase(screen->page,
1715 0, screen->state.cursor_y,
1716 screen->state.cursor_x, screen->state.cursor_y,
1717 &screen->state.attr, screen->age, true);
1720 term_page_erase(screen->page,
1721 0, screen->state.cursor_y,
1722 screen->page->width, screen->state.cursor_y,
1723 &screen->state.attr, screen->age, true);
1730 static int screen_DECSERA(term_screen *screen, const term_seq *seq) {
1732 * DECSERA - selective-erase-rectangular-area
1734 * Probably not worth implementing.
1740 static int screen_DECSFC(term_screen *screen, const term_seq *seq) {
1742 * DECSFC - select-flow-control
1744 * Probably not worth implementing.
1750 static int screen_DECSKCV(term_screen *screen, const term_seq *seq) {
1752 * DECSKCV - set-key-click-volume
1754 * Probably not worth implementing.
1760 static int screen_DECSLCK(term_screen *screen, const term_seq *seq) {
1762 * DECSLCK - set-lock-key-style
1764 * Probably not worth implementing.
1770 static int screen_DECSLE(term_screen *screen, const term_seq *seq) {
1772 * DECSLE - select-locator-events
1780 static int screen_DECSLPP(term_screen *screen, const term_seq *seq) {
1782 * DECSLPP - set-lines-per-page
1783 * Set the number of lines used for the page. @args[0] specifies the
1784 * number of lines to be used. DEC only allows a limited number of
1785 * choices, however, we allow all integers. 0 is equivalent to 24.
1796 static int screen_DECSLRM_OR_SC(term_screen *screen, const term_seq *seq) {
1798 * DECSLRM_OR_SC - set-left-and-right-margins or save-cursor
1800 * TODO: Detect save-cursor and run it. DECSLRM is not worth
1807 static int screen_DECSMBV(term_screen *screen, const term_seq *seq) {
1809 * DECSMBV - set-margin-bell-volume
1811 * Probably not worth implementing.
1817 static int screen_DECSMKR(term_screen *screen, const term_seq *seq) {
1819 * DECSMKR - select-modifier-key-reporting
1821 * Probably not worth implementing.
1827 static int screen_DECSNLS(term_screen *screen, const term_seq *seq) {
1829 * DECSNLS - set-lines-per-screen
1831 * Probably not worth implementing.
1837 static int screen_DECSPP(term_screen *screen, const term_seq *seq) {
1839 * DECSPP - set-port-parameter
1841 * Probably not worth implementing.
1847 static int screen_DECSPPCS(term_screen *screen, const term_seq *seq) {
1849 * DECSPPCS - select-pro-printer-character-set
1851 * Probably not worth implementing.
1857 static int screen_DECSPRTT(term_screen *screen, const term_seq *seq) {
1859 * DECSPRTT - select-printer-type
1861 * Probably not worth implementing.
1867 static int screen_DECSR(term_screen *screen, const term_seq *seq) {
1869 * DECSR - secure-reset
1871 * Probably not worth implementing.
1877 static int screen_DECSRFR(term_screen *screen, const term_seq *seq) {
1879 * DECSRFR - select-refresh-rate
1881 * Probably not worth implementing.
1887 static int screen_DECSSCLS(term_screen *screen, const term_seq *seq) {
1889 * DECSSCLS - set-scroll-speed
1891 * Probably not worth implementing.
1897 static int screen_DECSSDT(term_screen *screen, const term_seq *seq) {
1899 * DECSSDT - select-status-display-line-type
1901 * Probably not worth implementing.
1907 static int screen_DECSSL(term_screen *screen, const term_seq *seq) {
1909 * DECSSL - select-setup-language
1911 * Probably not worth implementing.
1917 static int screen_DECST8C(term_screen *screen, const term_seq *seq) {
1919 * DECST8C - set-tab-at-every-8-columns
1920 * Clear the tab-ruler and reset it to a tab at every 8th column,
1921 * starting at 9 (though, setting a tab at 1 is fine as it has no
1927 for (i = 0; i < screen->page->width; i += 8)
1928 screen->tabs[i / 8] = 0x1;
1933 static int screen_DECSTBM(term_screen *screen, const term_seq *seq) {
1935 * DECSTBM - set-top-and-bottom-margins
1936 * This control function sets the top and bottom margins for the current
1937 * page. You cannot perform scrolling outside the margins.
1939 * @args[0] defines the top margin, @args[1] defines the bottom margin.
1940 * The bottom margin must be lower than the top-margin.
1942 * This call resets the cursor position to 0/0 of the page.
1946 * args[1]: last page-line
1949 unsigned int top, bottom;
1952 bottom = screen->page->height;
1954 if (seq->args[0] > 0)
1956 if (seq->args[1] > 0)
1957 bottom = seq->args[1];
1959 if (top > screen->page->height)
1960 top = screen->page->height;
1961 if (bottom > screen->page->height)
1962 bottom = screen->page->height;
1964 if (top >= bottom || top > screen->page->height || bottom > screen->page->height) {
1966 bottom = screen->page->height;
1969 term_page_set_scroll_region(screen->page_main, top - 1, bottom - top + 1);
1970 term_page_set_scroll_region(screen->page_alt, top - 1, bottom - top + 1);
1971 screen_cursor_clear_wrap(screen);
1972 screen_cursor_set(screen, 0, 0);
1977 static int screen_DECSTR(term_screen *screen, const term_seq *seq) {
1979 * DECSTR - soft-terminal-reset
1980 * Perform a soft reset to the default values.
1983 term_screen_soft_reset(screen);
1988 static int screen_DECSTRL(term_screen *screen, const term_seq *seq) {
1990 * DECSTRL - set-transmit-rate-limit
1992 * Probably not worth implementing.
1998 static int screen_DECSWBV(term_screen *screen, const term_seq *seq) {
2000 * DECSWBV - set-warning-bell-volume
2002 * Probably not worth implementing.
2008 static int screen_DECSWL(term_screen *screen, const term_seq *seq) {
2010 * DECSWL - single-width-single-height-line
2012 * Probably not worth implementing.
2018 static int screen_DECTID(term_screen *screen, const term_seq *seq) {
2020 * DECTID - select-terminal-id
2022 * Probably not worth implementing.
2028 static int screen_DECTME(term_screen *screen, const term_seq *seq) {
2030 * DECTME - terminal-mode-emulation
2032 * Probably not worth implementing.
2038 static int screen_DECTST(term_screen *screen, const term_seq *seq) {
2040 * DECTST - invoke-confidence-test
2042 * Probably not worth implementing.
2048 static int screen_DL(term_screen *screen, const term_seq *seq) {
2051 * This control function deletes one or more lines in the scrolling
2052 * region, starting with the line that has the cursor. @args[0] defines
2053 * the number of lines to delete. 0 is treated the same as 1.
2054 * As lines are deleted, lines below the cursor and in the scrolling
2055 * region move up. The terminal adds blank lines with no visual
2056 * character attributes at the bottom of the scrolling region. If it is
2057 * greater than the number of lines remaining on the page, DL deletes
2058 * only the remaining lines. DL has no effect outside the scrolling
2065 unsigned int num = 1;
2067 if (seq->args[0] > 0)
2070 term_page_delete_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2075 static int screen_DSR_ANSI(term_screen *screen, const term_seq *seq) {
2077 * DSR_ANSI - device-status-report-ansi
2085 static int screen_DSR_DEC(term_screen *screen, const term_seq *seq) {
2087 * DSR_DEC - device-status-report-dec
2095 static int screen_ECH(term_screen *screen, const term_seq *seq) {
2097 * ECH - erase-character
2098 * This control function erases one or more characters, from the cursor
2099 * position to the right. ECH clears character attributes from erased
2100 * character positions. ECH works inside or outside the scrolling
2102 * @args[0] defines the number of characters to erase. 0 is treated the
2109 unsigned int num = 1;
2111 if (seq->args[0] > 0)
2114 term_page_erase(screen->page,
2115 screen->state.cursor_x, screen->state.cursor_y,
2116 screen->state.cursor_x + num, screen->state.cursor_y,
2117 &screen->state.attr, screen->age, false);
2122 static int screen_ED(term_screen *screen, const term_seq *seq) {
2124 * ED - erase-in-display
2125 * This control function erases characters from part or all of the
2126 * display. When you erase complete lines, they become single-height,
2127 * single-width lines, with all visual character attributes cleared. ED
2128 * works inside or outside the scrolling margins.
2130 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2131 * till the end of the screen. 1 means from the start of the screen till
2132 * the cursor (inclusive) and 2 means the whole screen.
2138 unsigned int mode = 0;
2140 if (seq->args[0] > 0)
2141 mode = seq->args[0];
2145 term_page_erase(screen->page,
2146 screen->state.cursor_x, screen->state.cursor_y,
2147 screen->page->width, screen->page->height,
2148 &screen->state.attr, screen->age, false);
2151 term_page_erase(screen->page,
2153 screen->state.cursor_x, screen->state.cursor_y,
2154 &screen->state.attr, screen->age, false);
2157 term_page_erase(screen->page,
2159 screen->page->width, screen->page->height,
2160 &screen->state.attr, screen->age, false);
2167 static int screen_EL(term_screen *screen, const term_seq *seq) {
2169 * EL - erase-in-line
2170 * This control function erases characters on the line that has the
2171 * cursor. EL clears all character attributes from erased character
2172 * positions. EL works inside or outside the scrolling margins.
2174 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2175 * till the end of the line. 1 means from the start of the line till the
2176 * cursor (inclusive) and 2 means the whole line.
2182 unsigned int mode = 0;
2184 if (seq->args[0] > 0)
2185 mode = seq->args[0];
2189 term_page_erase(screen->page,
2190 screen->state.cursor_x, screen->state.cursor_y,
2191 screen->page->width, screen->state.cursor_y,
2192 &screen->state.attr, screen->age, false);
2195 term_page_erase(screen->page,
2196 0, screen->state.cursor_y,
2197 screen->state.cursor_x, screen->state.cursor_y,
2198 &screen->state.attr, screen->age, false);
2201 term_page_erase(screen->page,
2202 0, screen->state.cursor_y,
2203 screen->page->width, screen->state.cursor_y,
2204 &screen->state.attr, screen->age, false);
2211 static int screen_ENQ(term_screen *screen, const term_seq *seq) {
2214 * Transmit the answerback-string. If none is set, do nothing.
2217 if (screen->answerback)
2218 return screen_write(screen, screen->answerback, strlen(screen->answerback));
2223 static int screen_EPA(term_screen *screen, const term_seq *seq) {
2225 * EPA - end-of-guarded-area
2227 * TODO: What is this?
2233 static int screen_FF(term_screen *screen, const term_seq *seq) {
2236 * This causes the cursor to jump to the next line. It is treated the
2240 return screen_LF(screen, seq);
2243 static int screen_HPA(term_screen *screen, const term_seq *seq) {
2245 * HPA - horizontal-position-absolute
2246 * HPA causes the active position to be moved to the n-th horizontal
2247 * position of the active line. If an attempt is made to move the active
2248 * position past the last position on the line, then the active position
2249 * stops at the last position on the line.
2251 * @args[0] defines the horizontal position. 0 is treated as 1.
2257 unsigned int num = 1;
2259 if (seq->args[0] > 0)
2262 screen_cursor_clear_wrap(screen);
2263 screen_cursor_set(screen, num - 1, screen->state.cursor_y);
2268 static int screen_HPR(term_screen *screen, const term_seq *seq) {
2270 * HPR - horizontal-position-relative
2271 * HPR causes the active position to be moved to the n-th following
2272 * horizontal position of the active line. If an attempt is made to move
2273 * the active position past the last position on the line, then the
2274 * active position stops at the last position on the line.
2276 * @args[0] defines the horizontal position. 0 is treated as 1.
2282 unsigned int num = 1;
2284 if (seq->args[0] > 0)
2287 screen_cursor_clear_wrap(screen);
2288 screen_cursor_right(screen, num);
2293 static int screen_HT(term_screen *screen, const term_seq *seq) {
2295 * HT - horizontal-tab
2296 * Moves the cursor to the next tab stop. If there are no more tab
2297 * stops, the cursor moves to the right margin. HT does not cause text
2301 screen_cursor_clear_wrap(screen);
2302 screen_cursor_right_tab(screen, 1);
2307 static int screen_HTS(term_screen *screen, const term_seq *seq) {
2309 * HTS - horizontal-tab-set
2310 * HTS sets a horizontal tab stop at the column position indicated by
2311 * the value of the active column when the terminal receives an HTS.
2313 * Executing an HTS does not effect the other horizontal tab stop
2319 pos = screen->state.cursor_x;
2320 if (screen->page->width > 0)
2321 screen->tabs[pos / 8] |= 1U << (pos % 8);
2326 static int screen_HVP(term_screen *screen, const term_seq *seq) {
2328 * HVP - horizontal-and-vertical-position
2329 * This control function works the same as the cursor position (CUP)
2330 * function. Origin mode (DECOM) selects line numbering and the ability
2331 * to move the cursor into margins.
2338 return screen_CUP(screen, seq);
2341 static int screen_ICH(term_screen *screen, const term_seq *seq) {
2343 * ICH - insert-character
2344 * This control function inserts one or more space (SP) characters
2345 * starting at the cursor position. @args[0] is the number of characters
2346 * to insert. 0 is treated as 1.
2348 * The ICH sequence inserts blank characters with the normal
2349 * character attribute. The cursor remains at the beginning of the blank
2350 * characters. Text between the cursor and right margin moves to the
2351 * right. Characters scrolled past the right margin are lost. ICH has no
2352 * effect outside the scrolling margins.
2358 unsigned int num = 1;
2360 if (seq->args[0] > 0)
2363 screen_cursor_clear_wrap(screen);
2364 term_page_insert_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2369 static int screen_IL(term_screen *screen, const term_seq *seq) {
2372 * This control function inserts one or more blank lines, starting at
2373 * the cursor. @args[0] is the number of lines to insert. 0 is treated
2376 * As lines are inserted, lines below the cursor and in the scrolling
2377 * region move down. Lines scrolled off the page are lost. IL has no
2378 * effect outside the page margins.
2384 unsigned int num = 1;
2386 if (seq->args[0] > 0)
2389 screen_cursor_clear_wrap(screen);
2390 term_page_insert_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2395 static int screen_IND(term_screen *screen, const term_seq *seq) {
2398 * IND moves the cursor down one line in the same column. If the cursor
2399 * is at the bottom margin, then the screen performs a scroll-up.
2402 screen_cursor_down(screen, 1, true);
2407 static int screen_LF(term_screen *screen, const term_seq *seq) {
2410 * Causes a line feed or a new line operation, depending on the setting
2411 * of line feed/new line mode.
2414 screen_cursor_down(screen, 1, true);
2415 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
2416 screen_cursor_left(screen, screen->state.cursor_x);
2421 static int screen_LS1R(term_screen *screen, const term_seq *seq) {
2423 * LS1R - locking-shift-1-right
2427 screen->state.gr = &screen->g1;
2432 static int screen_LS2(term_screen *screen, const term_seq *seq) {
2434 * LS2 - locking-shift-2
2438 screen->state.gl = &screen->g2;
2443 static int screen_LS2R(term_screen *screen, const term_seq *seq) {
2445 * LS2R - locking-shift-2-right
2449 screen->state.gr = &screen->g2;
2454 static int screen_LS3(term_screen *screen, const term_seq *seq) {
2456 * LS3 - locking-shift-3
2460 screen->state.gl = &screen->g3;
2465 static int screen_LS3R(term_screen *screen, const term_seq *seq) {
2467 * LS3R - locking-shift-3-right
2471 screen->state.gr = &screen->g3;
2476 static int screen_MC_ANSI(term_screen *screen, const term_seq *seq) {
2478 * MC_ANSI - media-copy-ansi
2480 * Probably not worth implementing.
2486 static int screen_MC_DEC(term_screen *screen, const term_seq *seq) {
2488 * MC_DEC - media-copy-dec
2490 * Probably not worth implementing.
2496 static int screen_NEL(term_screen *screen, const term_seq *seq) {
2499 * Moves cursor to first position on next line. If cursor is at bottom
2500 * margin, then screen performs a scroll-up.
2503 screen_cursor_clear_wrap(screen);
2504 screen_cursor_down(screen, 1, true);
2505 screen_cursor_set(screen, 0, screen->state.cursor_y);
2510 static int screen_NP(term_screen *screen, const term_seq *seq) {
2513 * This control function moves the cursor forward to the home position
2514 * on one of the following pages in page memory. If there is only one
2515 * page, then the terminal ignores NP.
2516 * If NP tries to move the cursor past the last page in memory, then the
2517 * cursor stops at the last page.
2519 * @args[0] defines the number of pages to forward. 0 is treated as 1.
2524 * Probably not worth implementing. We only support a single page.
2530 static int screen_NULL(term_screen *screen, const term_seq *seq) {
2533 * The NULL operation does nothing. ASCII NULL is always ignored.
2539 static int screen_PP(term_screen *screen, const term_seq *seq) {
2541 * PP - preceding-page
2542 * This control function moves the cursor backward to the home position
2543 * on one of the preceding pages in page memory. If there is only one
2544 * page, then the terminal ignores PP.
2545 * If PP tries to move the cursor back farther than the first page in
2546 * memory, then the cursor stops at the first page.
2548 * @args[0] defines the number of pages to go backwards. 0 is treated
2554 * Probably not worth implementing. We only support a single page.
2560 static int screen_PPA(term_screen *screen, const term_seq *seq) {
2562 * PPA - page-position-absolute
2563 * This control function can move the cursor to the corresponding row
2564 * and column on any page in page memory. You select the page by its
2565 * number. If there is only one page, then the terminal ignores PPA.
2567 * @args[0] is the number of the page to move the cursor to. If it is
2568 * greater than the number of the last page in memory, then the cursor
2569 * stops at the last page. If it is less than the number of the first
2570 * page, then the cursor stops at the first page.
2575 * Probably not worth implementing. We only support a single page.
2581 static int screen_PPB(term_screen *screen, const term_seq *seq) {
2583 * PPB - page-position-backward
2584 * This control function moves the cursor backward to the corresponding
2585 * row and column on one of the preceding pages in page memory. If there
2586 * is only one page, then the terminal ignores PPB.
2588 * @args[0] indicates the number of pages to move the cursor backward.
2589 * If it tries to move the cursor back farther than the first page in
2590 * memory, then the cursor stops at the first page. 0 is treated as 1.
2595 * Probably not worth implementing. We only support a single page.
2601 static int screen_PPR(term_screen *screen, const term_seq *seq) {
2603 * PPR - page-position-relative
2604 * This control function moves the cursor forward to the corresponding
2605 * row and column on one of the following pages in page memory. If there
2606 * is only one page, then the terminal ignores PPR.
2608 * @args[0] indicates how many pages to move the cursor forward. If it
2609 * tries to move the cursor beyond the last page in memory, then the
2610 * cursor stops at the last page. 0 is treated as 1.
2615 * Probably not worth implementing. We only support a single page.
2621 static int screen_RC(term_screen *screen, const term_seq *seq) {
2623 * RC - restore-cursor
2626 return screen_DECRC(screen, seq);
2629 static int screen_REP(term_screen *screen, const term_seq *seq) {
2632 * Repeat the preceding graphics-character the given number of times.
2633 * @args[0] specifies how often it shall be repeated. 0 is treated as 1.
2638 * Probably not worth implementing.
2644 static int screen_RI(term_screen *screen, const term_seq *seq) {
2646 * RI - reverse-index
2647 * Moves the cursor up one line in the same column. If the cursor is at
2648 * the top margin, the page scrolls down.
2651 screen_cursor_up(screen, 1, true);
2656 static int screen_RIS(term_screen *screen, const term_seq *seq) {
2658 * RIS - reset-to-initial-state
2659 * This control function causes a nonvolatile memory (NVR) recall to
2660 * occur. RIS replaces all set-up features with their saved settings.
2662 * The terminal stores these saved settings in NVR memory. The saved
2663 * setting for a feature is the same as the factory-default setting,
2664 * unless you saved a new setting.
2667 term_screen_hard_reset(screen);
2672 static int screen_RM_ANSI(term_screen *screen, const term_seq *seq) {
2674 * RM_ANSI - reset-mode-ansi
2676 * TODO: implement (see VT510rm manual)
2681 for (i = 0; i < seq->n_args; ++i)
2682 screen_mode_change(screen, seq->args[i], false, false);
2687 static int screen_RM_DEC(term_screen *screen, const term_seq *seq) {
2689 * RM_DEC - reset-mode-dec
2690 * This is the same as RM_ANSI but for DEC modes.
2695 for (i = 0; i < seq->n_args; ++i)
2696 screen_mode_change(screen, seq->args[i], true, false);
2701 static int screen_S7C1T(term_screen *screen, const term_seq *seq) {
2703 * S7C1T - set-7bit-c1-terminal
2704 * This causes the terminal to start sending C1 controls as 7bit
2705 * sequences instead of 8bit C1 controls.
2706 * This is ignored if the terminal is below level-2 emulation mode
2707 * (VT100 and below), the terminal already sends 7bit controls then.
2710 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2711 screen->flags |= TERM_FLAG_7BIT_MODE;
2716 static int screen_S8C1T(term_screen *screen, const term_seq *seq) {
2718 * S8C1T - set-8bit-c1-terminal
2719 * This causes the terminal to start sending C1 controls as 8bit C1
2720 * control instead of 7bit sequences.
2721 * This is ignored if the terminal is below level-2 emulation mode
2722 * (VT100 and below). The terminal always sends 7bit controls in those
2726 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2727 screen->flags &= ~TERM_FLAG_7BIT_MODE;
2732 static int screen_SCS(term_screen *screen, const term_seq *seq) {
2734 * SCS - select-character-set
2735 * Designate character sets to G-sets. The mapping from intermediates
2736 * and terminal characters in the escape sequence to G-sets and
2737 * character-sets is non-trivial and implemented separately. See there
2738 * for more information.
2739 * This call simply sets the selected G-set to the desired
2743 term_charset *cs = NULL;
2745 /* TODO: support more of them? */
2746 switch (seq->charset) {
2747 case TERM_CHARSET_ISO_LATIN1_SUPPLEMENTAL:
2748 case TERM_CHARSET_ISO_LATIN2_SUPPLEMENTAL:
2749 case TERM_CHARSET_ISO_LATIN5_SUPPLEMENTAL:
2750 case TERM_CHARSET_ISO_GREEK_SUPPLEMENTAL:
2751 case TERM_CHARSET_ISO_HEBREW_SUPPLEMENTAL:
2752 case TERM_CHARSET_ISO_LATIN_CYRILLIC:
2755 case TERM_CHARSET_DEC_SPECIAL_GRAPHIC:
2756 cs = &term_dec_special_graphics;
2758 case TERM_CHARSET_DEC_SUPPLEMENTAL:
2759 cs = &term_dec_supplemental_graphics;
2761 case TERM_CHARSET_DEC_TECHNICAL:
2762 case TERM_CHARSET_CYRILLIC_DEC:
2763 case TERM_CHARSET_DUTCH_NRCS:
2764 case TERM_CHARSET_FINNISH_NRCS:
2765 case TERM_CHARSET_FRENCH_NRCS:
2766 case TERM_CHARSET_FRENCH_CANADIAN_NRCS:
2767 case TERM_CHARSET_GERMAN_NRCS:
2768 case TERM_CHARSET_GREEK_DEC:
2769 case TERM_CHARSET_GREEK_NRCS:
2770 case TERM_CHARSET_HEBREW_DEC:
2771 case TERM_CHARSET_HEBREW_NRCS:
2772 case TERM_CHARSET_ITALIAN_NRCS:
2773 case TERM_CHARSET_NORWEGIAN_DANISH_NRCS:
2774 case TERM_CHARSET_PORTUGUESE_NRCS:
2775 case TERM_CHARSET_RUSSIAN_NRCS:
2776 case TERM_CHARSET_SCS_NRCS:
2777 case TERM_CHARSET_SPANISH_NRCS:
2778 case TERM_CHARSET_SWEDISH_NRCS:
2779 case TERM_CHARSET_SWISS_NRCS:
2780 case TERM_CHARSET_TURKISH_DEC:
2781 case TERM_CHARSET_TURKISH_NRCS:
2784 case TERM_CHARSET_USERPREF_SUPPLEMENTAL:
2788 if (seq->intermediates & TERM_SEQ_FLAG_POPEN)
2789 screen->g0 = cs ? : &term_unicode_lower;
2790 else if (seq->intermediates & TERM_SEQ_FLAG_PCLOSE)
2791 screen->g1 = cs ? : &term_unicode_upper;
2792 else if (seq->intermediates & TERM_SEQ_FLAG_MULT)
2793 screen->g2 = cs ? : &term_unicode_lower;
2794 else if (seq->intermediates & TERM_SEQ_FLAG_PLUS)
2795 screen->g3 = cs ? : &term_unicode_upper;
2796 else if (seq->intermediates & TERM_SEQ_FLAG_MINUS)
2797 screen->g1 = cs ? : &term_unicode_upper;
2798 else if (seq->intermediates & TERM_SEQ_FLAG_DOT)
2799 screen->g2 = cs ? : &term_unicode_lower;
2800 else if (seq->intermediates & TERM_SEQ_FLAG_SLASH)
2801 screen->g3 = cs ? : &term_unicode_upper;
2806 static int screen_SD(term_screen *screen, const term_seq *seq) {
2809 * This control function moves the user window down a specified number
2810 * of lines in page memory.
2811 * @args[0] is the number of lines to move the
2812 * user window up in page memory. New lines appear at the top of the
2813 * display. Old lines disappear at the bottom of the display. You
2814 * cannot pan past the top margin of the current page. 0 is treated
2821 unsigned int num = 1;
2823 if (seq->args[0] > 0)
2826 term_page_scroll_down(screen->page, num, &screen->state.attr, screen->age, NULL);
2831 static int screen_SGR(term_screen *screen, const term_seq *seq) {
2833 * SGR - select-graphics-rendition
2837 unsigned int i, code;
2840 if (seq->n_args < 1) {
2841 zero(screen->state.attr);
2845 for (i = 0; i < seq->n_args; ++i) {
2849 screen->state.attr.bold = 1;
2852 screen->state.attr.italic = 1;
2855 screen->state.attr.underline = 1;
2858 screen->state.attr.blink = 1;
2861 screen->state.attr.inverse = 1;
2864 screen->state.attr.hidden = 1;
2867 screen->state.attr.bold = 0;
2870 screen->state.attr.italic = 0;
2873 screen->state.attr.underline = 0;
2876 screen->state.attr.blink = 0;
2879 screen->state.attr.inverse = 0;
2882 screen->state.attr.hidden = 0;
2885 screen->state.attr.fg.ccode = v - 30 + TERM_CCODE_BLACK;
2888 screen->state.attr.fg.ccode = 0;
2891 screen->state.attr.bg.ccode = v - 40 + TERM_CCODE_BLACK;
2894 screen->state.attr.bg.ccode = 0;
2897 screen->state.attr.fg.ccode = v - 90 + TERM_CCODE_LIGHT_BLACK;
2900 screen->state.attr.bg.ccode = v - 100 + TERM_CCODE_LIGHT_BLACK;
2907 dst = &screen->state.attr.fg;
2909 dst = &screen->state.attr.bg;
2912 if (i >= seq->n_args)
2915 switch (seq->args[i]) {
2917 /* 24bit-color support */
2920 if (i >= seq->n_args)
2923 dst->ccode = TERM_CCODE_RGB;
2924 dst->red = (seq->args[i - 2] >= 0) ? seq->args[i - 2] : 0;
2925 dst->green = (seq->args[i - 1] >= 0) ? seq->args[i - 1] : 0;
2926 dst->blue = (seq->args[i] >= 0) ? seq->args[i] : 0;
2930 /* 256-color support */
2933 if (i >= seq->n_args || seq->args[i] < 0)
2936 dst->ccode = TERM_CCODE_256;
2937 code = seq->args[i];
2938 dst->c256 = code < 256 ? code : 0;
2947 zero(screen->state.attr);
2955 static int screen_SI(term_screen *screen, const term_seq *seq) {
2961 screen->state.gl = &screen->g0;
2966 static int screen_SM_ANSI(term_screen *screen, const term_seq *seq) {
2968 * SM_ANSI - set-mode-ansi
2975 for (i = 0; i < seq->n_args; ++i)
2976 screen_mode_change(screen, seq->args[i], false, true);
2981 static int screen_SM_DEC(term_screen *screen, const term_seq *seq) {
2983 * SM_DEC - set-mode-dec
2984 * This is the same as SM_ANSI but for DEC modes.
2989 for (i = 0; i < seq->n_args; ++i)
2990 screen_mode_change(screen, seq->args[i], true, true);
2995 static int screen_SO(term_screen *screen, const term_seq *seq) {
3001 screen->state.gl = &screen->g1;
3006 static int screen_SPA(term_screen *screen, const term_seq *seq) {
3008 * SPA - start-of-protected-area
3010 * TODO: What is this?
3016 static int screen_SS2(term_screen *screen, const term_seq *seq) {
3018 * SS2 - single-shift-2
3019 * Temporarily map G2 into GL for the next graphics character.
3022 screen->state.glt = &screen->g2;
3027 static int screen_SS3(term_screen *screen, const term_seq *seq) {
3029 * SS3 - single-shift-3
3030 * Temporarily map G3 into GL for the next graphics character
3033 screen->state.glt = &screen->g3;
3038 static int screen_ST(term_screen *screen, const term_seq *seq) {
3040 * ST - string-terminator
3041 * The string-terminator is usually part of control-sequences and
3042 * handled by the parser. In all other situations it is silently
3049 static int screen_SU(term_screen *screen, const term_seq *seq) {
3052 * This control function moves the user window up a specified number of
3053 * lines in page memory.
3054 * @args[0] is the number of lines to move the
3055 * user window down in page memory. New lines appear at the bottom of
3056 * the display. Old lines disappear at the top of the display. You
3057 * cannot pan past the bottom margin of the current page. 0 is treated
3064 unsigned int num = 1;
3066 if (seq->args[0] > 0)
3069 term_page_scroll_up(screen->page, num, &screen->state.attr, screen->age, screen->history);
3074 static int screen_SUB(term_screen *screen, const term_seq *seq) {
3077 * Cancel the current control-sequence and print a replacement
3078 * character. Our parser already handles this so all we have to do is
3079 * print the replacement character.
3082 static const term_seq rep = {
3083 .type = TERM_SEQ_GRAPHIC,
3084 .command = TERM_CMD_GRAPHIC,
3085 .terminator = 0xfffd,
3088 return screen_GRAPHIC(screen, &rep);
3091 static int screen_TBC(term_screen *screen, const term_seq *seq) {
3094 * This clears tab-stops. If @args[0] is 0, the tab-stop at the current
3095 * cursor position is cleared. If it is 3, all tab stops are cleared.
3101 unsigned int mode = 0, pos;
3103 if (seq->args[0] > 0)
3104 mode = seq->args[0];
3108 pos = screen->state.cursor_x;
3109 if (screen->page->width > 0)
3110 screen->tabs[pos / 8] &= ~(1U << (pos % 8));
3113 if (screen->page->width > 0)
3114 memset(screen->tabs, 0, (screen->page->width + 7) / 8);
3121 static int screen_VPA(term_screen *screen, const term_seq *seq) {
3123 * VPA - vertical-line-position-absolute
3124 * VPA causes the active position to be moved to the corresponding
3125 * horizontal position. @args[0] specifies the line to jump to. If an
3126 * attempt is made to move the active position below the last line, then
3127 * the active position stops on the last line. 0 is treated as 1.
3133 unsigned int pos = 1;
3135 if (seq->args[0] > 0)
3138 screen_cursor_clear_wrap(screen);
3139 screen_cursor_set_rel(screen, screen->state.cursor_x, pos - 1);
3144 static int screen_VPR(term_screen *screen, const term_seq *seq) {
3146 * VPR - vertical-line-position-relative
3147 * VPR causes the active position to be moved to the corresponding
3148 * horizontal position. @args[0] specifies the number of lines to jump
3149 * down relative to the current cursor position. If an attempt is made
3150 * to move the active position below the last line, the active position
3151 * stops at the last line. 0 is treated as 1.
3157 unsigned int num = 1;
3159 if (seq->args[0] > 0)
3162 screen_cursor_clear_wrap(screen);
3163 screen_cursor_down(screen, num, false);
3168 static int screen_VT(term_screen *screen, const term_seq *seq) {
3171 * This causes a vertical jump by one line. Terminals treat it exactly
3175 return screen_LF(screen, seq);
3178 static int screen_XTERM_CLLHP(term_screen *screen, const term_seq *seq) {
3180 * XTERM_CLLHP - xterm-cursor-lower-left-hp-bugfix
3181 * Move the cursor to the lower-left corner of the page. This is an HP
3184 * Probably not worth implementing.
3190 static int screen_XTERM_IHMT(term_screen *screen, const term_seq *seq) {
3192 * XTERM_IHMT - xterm-initiate-highlight-mouse-tracking
3194 * Probably not worth implementing.
3200 static int screen_XTERM_MLHP(term_screen *screen, const term_seq *seq) {
3202 * XTERM_MLHP - xterm-memory-lock-hp-bugfix
3204 * Probably not worth implementing.
3210 static int screen_XTERM_MUHP(term_screen *screen, const term_seq *seq) {
3212 * XTERM_MUHP - xterm-memory-unlock-hp-bugfix
3214 * Probably not worth implementing.
3220 static int screen_XTERM_RPM(term_screen *screen, const term_seq *seq) {
3222 * XTERM_RPM - xterm-restore-private-mode
3224 * Probably not worth implementing.
3230 static int screen_XTERM_RRV(term_screen *screen, const term_seq *seq) {
3232 * XTERM_RRV - xterm-reset-resource-value
3234 * Probably not worth implementing.
3240 static int screen_XTERM_RTM(term_screen *screen, const term_seq *seq) {
3242 * XTERM_RTM - xterm-reset-title-mode
3244 * Probably not worth implementing.
3250 static int screen_XTERM_SACL1(term_screen *screen, const term_seq *seq) {
3252 * XTERM_SACL1 - xterm-set-ansi-conformance-level-1
3254 * Probably not worth implementing.
3260 static int screen_XTERM_SACL2(term_screen *screen, const term_seq *seq) {
3262 * XTERM_SACL2 - xterm-set-ansi-conformance-level-2
3264 * Probably not worth implementing.
3270 static int screen_XTERM_SACL3(term_screen *screen, const term_seq *seq) {
3272 * XTERM_SACL3 - xterm-set-ansi-conformance-level-3
3274 * Probably not worth implementing.
3280 static int screen_XTERM_SDCS(term_screen *screen, const term_seq *seq) {
3282 * XTERM_SDCS - xterm-set-default-character-set
3283 * Select the default character set. We treat this the same as UTF-8 as
3284 * this is our default character set. As we always use UTF-8, this
3291 static int screen_XTERM_SGFX(term_screen *screen, const term_seq *seq) {
3293 * XTERM_SGFX - xterm-sixel-graphics
3295 * Probably not worth implementing.
3301 static int screen_XTERM_SPM(term_screen *screen, const term_seq *seq) {
3303 * XTERM_SPM - xterm-set-private-mode
3305 * Probably not worth implementing.
3311 static int screen_XTERM_SRV(term_screen *screen, const term_seq *seq) {
3313 * XTERM_SRV - xterm-set-resource-value
3315 * Probably not worth implementing.
3321 static int screen_XTERM_STM(term_screen *screen, const term_seq *seq) {
3323 * XTERM_STM - xterm-set-title-mode
3325 * Probably not worth implementing.
3331 static int screen_XTERM_SUCS(term_screen *screen, const term_seq *seq) {
3333 * XTERM_SUCS - xterm-select-utf8-character-set
3334 * Select UTF-8 as character set. This is our default on only character
3335 * set. Hence, this is a no-op.
3341 static int screen_XTERM_WM(term_screen *screen, const term_seq *seq) {
3343 * XTERM_WM - xterm-window-management
3345 * Probably not worth implementing.
3353 * The screen_feed_*() handlers take data from the user and feed it into the
3354 * screen. Once the parser has detected a sequence, we parse the command-type
3355 * and forward it to the command-dispatchers.
3358 static int screen_feed_cmd(term_screen *screen, const term_seq *seq) {
3359 switch (seq->command) {
3360 case TERM_CMD_GRAPHIC:
3361 return screen_GRAPHIC(screen, seq);
3363 return screen_BEL(screen, seq);
3365 return screen_BS(screen, seq);
3367 return screen_CBT(screen, seq);
3369 return screen_CHA(screen, seq);
3371 return screen_CHT(screen, seq);
3373 return screen_CNL(screen, seq);
3375 return screen_CPL(screen, seq);
3377 return screen_CR(screen, seq);
3379 return screen_CUB(screen, seq);
3381 return screen_CUD(screen, seq);
3383 return screen_CUF(screen, seq);
3385 return screen_CUP(screen, seq);
3387 return screen_CUU(screen, seq);
3389 return screen_DA1(screen, seq);
3391 return screen_DA2(screen, seq);
3393 return screen_DA3(screen, seq);
3395 return screen_DC1(screen, seq);
3397 return screen_DC3(screen, seq);
3399 return screen_DCH(screen, seq);
3400 case TERM_CMD_DECALN:
3401 return screen_DECALN(screen, seq);
3402 case TERM_CMD_DECANM:
3403 return screen_DECANM(screen, seq);
3404 case TERM_CMD_DECBI:
3405 return screen_DECBI(screen, seq);
3406 case TERM_CMD_DECCARA:
3407 return screen_DECCARA(screen, seq);
3408 case TERM_CMD_DECCRA:
3409 return screen_DECCRA(screen, seq);
3410 case TERM_CMD_DECDC:
3411 return screen_DECDC(screen, seq);
3412 case TERM_CMD_DECDHL_BH:
3413 return screen_DECDHL_BH(screen, seq);
3414 case TERM_CMD_DECDHL_TH:
3415 return screen_DECDHL_TH(screen, seq);
3416 case TERM_CMD_DECDWL:
3417 return screen_DECDWL(screen, seq);
3418 case TERM_CMD_DECEFR:
3419 return screen_DECEFR(screen, seq);
3420 case TERM_CMD_DECELF:
3421 return screen_DECELF(screen, seq);
3422 case TERM_CMD_DECELR:
3423 return screen_DECELR(screen, seq);
3424 case TERM_CMD_DECERA:
3425 return screen_DECERA(screen, seq);
3426 case TERM_CMD_DECFI:
3427 return screen_DECFI(screen, seq);
3428 case TERM_CMD_DECFRA:
3429 return screen_DECFRA(screen, seq);
3430 case TERM_CMD_DECIC:
3431 return screen_DECIC(screen, seq);
3432 case TERM_CMD_DECID:
3433 return screen_DECID(screen, seq);
3434 case TERM_CMD_DECINVM:
3435 return screen_DECINVM(screen, seq);
3436 case TERM_CMD_DECKBD:
3437 return screen_DECKBD(screen, seq);
3438 case TERM_CMD_DECKPAM:
3439 return screen_DECKPAM(screen, seq);
3440 case TERM_CMD_DECKPNM:
3441 return screen_DECKPNM(screen, seq);
3442 case TERM_CMD_DECLFKC:
3443 return screen_DECLFKC(screen, seq);
3444 case TERM_CMD_DECLL:
3445 return screen_DECLL(screen, seq);
3446 case TERM_CMD_DECLTOD:
3447 return screen_DECLTOD(screen, seq);
3448 case TERM_CMD_DECPCTERM:
3449 return screen_DECPCTERM(screen, seq);
3450 case TERM_CMD_DECPKA:
3451 return screen_DECPKA(screen, seq);
3452 case TERM_CMD_DECPKFMR:
3453 return screen_DECPKFMR(screen, seq);
3454 case TERM_CMD_DECRARA:
3455 return screen_DECRARA(screen, seq);
3456 case TERM_CMD_DECRC:
3457 return screen_DECRC(screen, seq);
3458 case TERM_CMD_DECREQTPARM:
3459 return screen_DECREQTPARM(screen, seq);
3460 case TERM_CMD_DECRPKT:
3461 return screen_DECRPKT(screen, seq);
3462 case TERM_CMD_DECRQCRA:
3463 return screen_DECRQCRA(screen, seq);
3464 case TERM_CMD_DECRQDE:
3465 return screen_DECRQDE(screen, seq);
3466 case TERM_CMD_DECRQKT:
3467 return screen_DECRQKT(screen, seq);
3468 case TERM_CMD_DECRQLP:
3469 return screen_DECRQLP(screen, seq);
3470 case TERM_CMD_DECRQM_ANSI:
3471 return screen_DECRQM_ANSI(screen, seq);
3472 case TERM_CMD_DECRQM_DEC:
3473 return screen_DECRQM_DEC(screen, seq);
3474 case TERM_CMD_DECRQPKFM:
3475 return screen_DECRQPKFM(screen, seq);
3476 case TERM_CMD_DECRQPSR:
3477 return screen_DECRQPSR(screen, seq);
3478 case TERM_CMD_DECRQTSR:
3479 return screen_DECRQTSR(screen, seq);
3480 case TERM_CMD_DECRQUPSS:
3481 return screen_DECRQUPSS(screen, seq);
3482 case TERM_CMD_DECSACE:
3483 return screen_DECSACE(screen, seq);
3484 case TERM_CMD_DECSASD:
3485 return screen_DECSASD(screen, seq);
3486 case TERM_CMD_DECSC:
3487 return screen_DECSC(screen, seq);
3488 case TERM_CMD_DECSCA:
3489 return screen_DECSCA(screen, seq);
3490 case TERM_CMD_DECSCL:
3491 return screen_DECSCL(screen, seq);
3492 case TERM_CMD_DECSCP:
3493 return screen_DECSCP(screen, seq);
3494 case TERM_CMD_DECSCPP:
3495 return screen_DECSCPP(screen, seq);
3496 case TERM_CMD_DECSCS:
3497 return screen_DECSCS(screen, seq);
3498 case TERM_CMD_DECSCUSR:
3499 return screen_DECSCUSR(screen, seq);
3500 case TERM_CMD_DECSDDT:
3501 return screen_DECSDDT(screen, seq);
3502 case TERM_CMD_DECSDPT:
3503 return screen_DECSDPT(screen, seq);
3504 case TERM_CMD_DECSED:
3505 return screen_DECSED(screen, seq);
3506 case TERM_CMD_DECSEL:
3507 return screen_DECSEL(screen, seq);
3508 case TERM_CMD_DECSERA:
3509 return screen_DECSERA(screen, seq);
3510 case TERM_CMD_DECSFC:
3511 return screen_DECSFC(screen, seq);
3512 case TERM_CMD_DECSKCV:
3513 return screen_DECSKCV(screen, seq);
3514 case TERM_CMD_DECSLCK:
3515 return screen_DECSLCK(screen, seq);
3516 case TERM_CMD_DECSLE:
3517 return screen_DECSLE(screen, seq);
3518 case TERM_CMD_DECSLPP:
3519 return screen_DECSLPP(screen, seq);
3520 case TERM_CMD_DECSLRM_OR_SC:
3521 return screen_DECSLRM_OR_SC(screen, seq);
3522 case TERM_CMD_DECSMBV:
3523 return screen_DECSMBV(screen, seq);
3524 case TERM_CMD_DECSMKR:
3525 return screen_DECSMKR(screen, seq);
3526 case TERM_CMD_DECSNLS:
3527 return screen_DECSNLS(screen, seq);
3528 case TERM_CMD_DECSPP:
3529 return screen_DECSPP(screen, seq);
3530 case TERM_CMD_DECSPPCS:
3531 return screen_DECSPPCS(screen, seq);
3532 case TERM_CMD_DECSPRTT:
3533 return screen_DECSPRTT(screen, seq);
3534 case TERM_CMD_DECSR:
3535 return screen_DECSR(screen, seq);
3536 case TERM_CMD_DECSRFR:
3537 return screen_DECSRFR(screen, seq);
3538 case TERM_CMD_DECSSCLS:
3539 return screen_DECSSCLS(screen, seq);
3540 case TERM_CMD_DECSSDT:
3541 return screen_DECSSDT(screen, seq);
3542 case TERM_CMD_DECSSL:
3543 return screen_DECSSL(screen, seq);
3544 case TERM_CMD_DECST8C:
3545 return screen_DECST8C(screen, seq);
3546 case TERM_CMD_DECSTBM:
3547 return screen_DECSTBM(screen, seq);
3548 case TERM_CMD_DECSTR:
3549 return screen_DECSTR(screen, seq);
3550 case TERM_CMD_DECSTRL:
3551 return screen_DECSTRL(screen, seq);
3552 case TERM_CMD_DECSWBV:
3553 return screen_DECSWBV(screen, seq);
3554 case TERM_CMD_DECSWL:
3555 return screen_DECSWL(screen, seq);
3556 case TERM_CMD_DECTID:
3557 return screen_DECTID(screen, seq);
3558 case TERM_CMD_DECTME:
3559 return screen_DECTME(screen, seq);
3560 case TERM_CMD_DECTST:
3561 return screen_DECTST(screen, seq);
3563 return screen_DL(screen, seq);
3564 case TERM_CMD_DSR_ANSI:
3565 return screen_DSR_ANSI(screen, seq);
3566 case TERM_CMD_DSR_DEC:
3567 return screen_DSR_DEC(screen, seq);
3569 return screen_ECH(screen, seq);
3571 return screen_ED(screen, seq);
3573 return screen_EL(screen, seq);
3575 return screen_ENQ(screen, seq);
3577 return screen_EPA(screen, seq);
3579 return screen_FF(screen, seq);
3581 return screen_HPA(screen, seq);
3583 return screen_HPR(screen, seq);
3585 return screen_HT(screen, seq);
3587 return screen_HTS(screen, seq);
3589 return screen_HVP(screen, seq);
3591 return screen_ICH(screen, seq);
3593 return screen_IL(screen, seq);
3595 return screen_IND(screen, seq);
3597 return screen_LF(screen, seq);
3599 return screen_LS1R(screen, seq);
3601 return screen_LS2(screen, seq);
3603 return screen_LS2R(screen, seq);
3605 return screen_LS3(screen, seq);
3607 return screen_LS3R(screen, seq);
3608 case TERM_CMD_MC_ANSI:
3609 return screen_MC_ANSI(screen, seq);
3610 case TERM_CMD_MC_DEC:
3611 return screen_MC_DEC(screen, seq);
3613 return screen_NEL(screen, seq);
3615 return screen_NP(screen, seq);
3617 return screen_NULL(screen, seq);
3619 return screen_PP(screen, seq);
3621 return screen_PPA(screen, seq);
3623 return screen_PPB(screen, seq);
3625 return screen_PPR(screen, seq);
3627 return screen_RC(screen, seq);
3629 return screen_REP(screen, seq);
3631 return screen_RI(screen, seq);
3633 return screen_RIS(screen, seq);
3634 case TERM_CMD_RM_ANSI:
3635 return screen_RM_ANSI(screen, seq);
3636 case TERM_CMD_RM_DEC:
3637 return screen_RM_DEC(screen, seq);
3638 case TERM_CMD_S7C1T:
3639 return screen_S7C1T(screen, seq);
3640 case TERM_CMD_S8C1T:
3641 return screen_S8C1T(screen, seq);
3643 return screen_SCS(screen, seq);
3645 return screen_SD(screen, seq);
3647 return screen_SGR(screen, seq);
3649 return screen_SI(screen, seq);
3650 case TERM_CMD_SM_ANSI:
3651 return screen_SM_ANSI(screen, seq);
3652 case TERM_CMD_SM_DEC:
3653 return screen_SM_DEC(screen, seq);
3655 return screen_SO(screen, seq);
3657 return screen_SPA(screen, seq);
3659 return screen_SS2(screen, seq);
3661 return screen_SS3(screen, seq);
3663 return screen_ST(screen, seq);
3665 return screen_SU(screen, seq);
3667 return screen_SUB(screen, seq);
3669 return screen_TBC(screen, seq);
3671 return screen_VPA(screen, seq);
3673 return screen_VPR(screen, seq);
3675 return screen_VT(screen, seq);
3676 case TERM_CMD_XTERM_CLLHP:
3677 return screen_XTERM_CLLHP(screen, seq);
3678 case TERM_CMD_XTERM_IHMT:
3679 return screen_XTERM_IHMT(screen, seq);
3680 case TERM_CMD_XTERM_MLHP:
3681 return screen_XTERM_MLHP(screen, seq);
3682 case TERM_CMD_XTERM_MUHP:
3683 return screen_XTERM_MUHP(screen, seq);
3684 case TERM_CMD_XTERM_RPM:
3685 return screen_XTERM_RPM(screen, seq);
3686 case TERM_CMD_XTERM_RRV:
3687 return screen_XTERM_RRV(screen, seq);
3688 case TERM_CMD_XTERM_RTM:
3689 return screen_XTERM_RTM(screen, seq);
3690 case TERM_CMD_XTERM_SACL1:
3691 return screen_XTERM_SACL1(screen, seq);
3692 case TERM_CMD_XTERM_SACL2:
3693 return screen_XTERM_SACL2(screen, seq);
3694 case TERM_CMD_XTERM_SACL3:
3695 return screen_XTERM_SACL3(screen, seq);
3696 case TERM_CMD_XTERM_SDCS:
3697 return screen_XTERM_SDCS(screen, seq);
3698 case TERM_CMD_XTERM_SGFX:
3699 return screen_XTERM_SGFX(screen, seq);
3700 case TERM_CMD_XTERM_SPM:
3701 return screen_XTERM_SPM(screen, seq);
3702 case TERM_CMD_XTERM_SRV:
3703 return screen_XTERM_SRV(screen, seq);
3704 case TERM_CMD_XTERM_STM:
3705 return screen_XTERM_STM(screen, seq);
3706 case TERM_CMD_XTERM_SUCS:
3707 return screen_XTERM_SUCS(screen, seq);
3708 case TERM_CMD_XTERM_WM:
3709 return screen_XTERM_WM(screen, seq);
3715 unsigned int term_screen_get_width(term_screen *screen) {
3716 assert_return(screen, -EINVAL);
3718 return screen->page->width;
3721 unsigned int term_screen_get_height(term_screen *screen) {
3722 assert_return(screen, -EINVAL);
3724 return screen->page->height;
3727 uint64_t term_screen_get_age(term_screen *screen) {
3728 assert_return(screen, 0);
3733 int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) {
3735 size_t i, j, ucs4_len;
3736 const term_seq *seq;
3739 assert_return(screen, -EINVAL);
3743 /* Feed bytes into utf8 decoder and handle parsed ucs4 chars. We always
3744 * treat data as UTF-8, but the parser makes sure to fall back to raw
3745 * 8bit mode if the stream is not valid UTF-8. This should be more than
3746 * enough to support old 7bit/8bit modes. */
3747 for (i = 0; i < size; ++i) {
3748 ucs4_len = term_utf8_decode(&screen->utf8, &ucs4_str, in[i]);
3749 for (j = 0; j < ucs4_len; ++j) {
3750 r = term_parser_feed(screen->parser, &seq, ucs4_str[j]);
3753 } else if (r != TERM_SEQ_NONE) {
3754 r = screen_feed_cmd(screen, seq);
3764 static char *screen_map_key(term_screen *screen,
3766 const uint32_t *keysyms,
3769 const uint32_t *ucs4,
3770 unsigned int mods) {
3771 char ch, ch2, ch_mods;
3775 /* TODO: All these key-mappings need to be verified. Public information
3776 * on those mappings is pretty scarce and every emulator seems to do it
3777 * slightly differently.
3778 * A lot of mappings are also missing. */
3786 v = XKB_KEY_NoSymbol;
3788 /* In some mappings, the modifiers are encoded as CSI parameters. The
3789 * encoding is rather arbitrary, but seems to work. */
3791 switch (mods & (TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT | TERM_KBDMOD_CTRL)) {
3792 case TERM_KBDMOD_SHIFT:
3795 case TERM_KBDMOD_ALT:
3798 case TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3801 case TERM_KBDMOD_CTRL:
3804 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT:
3807 case TERM_KBDMOD_CTRL | TERM_KBDMOD_ALT:
3810 case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3815 /* A user might actually use multiple layouts for keyboard
3816 * input. @keysyms[0] contains the actual keysym that the user
3817 * used. But if this keysym is not in the ascii range, the
3818 * input handler does check all other layouts that the user
3819 * specified whether one of them maps the key to some ASCII
3820 * keysym and provides this via @ascii. We always use the real
3821 * keysym except when handling CTRL+<XY> shortcuts we use the
3822 * ascii keysym. This is for compatibility to xterm et. al. so
3823 * ctrl+c always works regardless of the currently active
3824 * keyboard layout. But if no ascii-sym is found, we still use
3825 * the real keysym. */
3826 if (ascii == XKB_KEY_NoSymbol)
3829 /* map CTRL+<ascii> */
3830 if (mods & TERM_KBDMOD_CTRL) {
3833 /* Right hand side is mapped to the left and then
3834 * treated equally. Fall through to left-hand side.. */
3837 /* Printable ASCII is mapped 1-1 in XKB and in
3838 * combination with CTRL bit 7 is flipped. This
3839 * is equivalent to the caret-notation. */
3840 *p++ = ascii ^ 0x40;
3845 /* map cursor keys */
3869 if (screen->flags & TERM_FLAG_CURSOR_KEYS)
3882 /* map action keys */
3888 case XKB_KEY_Insert:
3891 case XKB_KEY_Delete:
3894 case XKB_KEY_Select:
3897 case XKB_KEY_Page_Up:
3900 case XKB_KEY_Page_Down:
3916 /* map lower function keys */
3949 /* map upper function keys */
4000 /* map special keys */
4002 case 0xff08: /* XKB_KEY_BackSpace */
4003 case 0xff09: /* XKB_KEY_Tab */
4004 case 0xff0a: /* XKB_KEY_Linefeed */
4005 case 0xff0b: /* XKB_KEY_Clear */
4006 case 0xff15: /* XKB_KEY_Sys_Req */
4007 case 0xff1b: /* XKB_KEY_Escape */
4008 case 0xffff: /* XKB_KEY_Delete */
4011 case 0xff13: /* XKB_KEY_Pause */
4012 /* TODO: What should we do with this key?
4013 * Sending XOFF is awful as there is no simple
4014 * way on modern keyboards to send XON again.
4015 * If someone wants this, we can re-eanble
4018 case 0xff14: /* XKB_KEY_Scroll_Lock */
4019 /* TODO: What should we do on scroll-lock?
4020 * Sending 0x14 is what the specs say but it is
4021 * not used today the way most users would
4022 * expect so we disable it. If someone wants
4023 * this, we can re-enable it (optionally). */
4025 case XKB_KEY_Return:
4027 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
4030 case XKB_KEY_ISO_Left_Tab:
4035 /* map unicode keys */
4036 for (i = 0; i < n_syms; ++i)
4037 p += term_utf8_encode(p, ucs4[i]);
4042 int term_screen_feed_keyboard(term_screen *screen,
4043 const uint32_t *keysyms,
4046 const uint32_t *ucs4,
4047 unsigned int mods) {
4048 _cleanup_free_ char *dyn = NULL;
4049 static const size_t padding = 1;
4050 char buf[128], *start, *p = buf;
4052 assert_return(screen, -EINVAL);
4054 /* allocate buffer if too small */
4056 if (4 * n_syms + padding > sizeof(buf)) {
4057 dyn = malloc(4 * n_syms + padding);
4064 /* reserve prefix space */
4068 p = screen_map_key(screen, p, keysyms, n_syms, ascii, ucs4, mods);
4069 if (!p || p - start < 1)
4072 /* The ALT modifier causes ESC to be prepended to any key-stroke. We
4073 * already accounted for that buffer space above, so simply prepend it
4075 * TODO: is altSendsEscape a suitable default? What are the semantics
4076 * exactly? Is it used in C0/C1 conversion? Is it prepended if there
4077 * already is an escape character? */
4078 if (mods & TERM_KBDMOD_ALT && *start != 0x1b)
4081 /* turn C0 into C1 */
4082 if (!(screen->flags & TERM_FLAG_7BIT_MODE) && p - start >= 2)
4083 if (start[0] == 0x1b && start[1] >= 0x40 && start[1] <= 0x5f)
4086 return screen_write(screen, start, p - start);
4089 int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) {
4094 assert_return(screen, -EINVAL);
4096 r = term_page_reserve(screen->page_main, x, y, &screen->state.attr, screen->age);
4100 r = term_page_reserve(screen->page_alt, x, y, &screen->state.attr, screen->age);
4104 if (x > screen->n_tabs) {
4105 t = realloc(screen->tabs, (x + 7) / 8);
4113 for (i = (screen->page->width + 7) / 8 * 8; i < x; i += 8)
4114 screen->tabs[i / 8] = 0x1;
4116 term_page_resize(screen->page_main, x, y, &screen->state.attr, screen->age, screen->history);
4117 term_page_resize(screen->page_alt, x, y, &screen->state.attr, screen->age, NULL);
4119 screen->state.cursor_x = screen_clamp_x(screen, screen->state.cursor_x);
4120 screen->state.cursor_y = screen_clamp_x(screen, screen->state.cursor_y);
4121 screen_cursor_clear_wrap(screen);
4126 void term_screen_soft_reset(term_screen *screen) {
4131 screen->g0 = &term_unicode_lower;
4132 screen->g1 = &term_unicode_upper;
4133 screen->g2 = &term_unicode_lower;
4134 screen->g3 = &term_unicode_upper;
4135 screen->state.attr = screen->default_attr;
4136 screen->state.gl = &screen->g0;
4137 screen->state.gr = &screen->g1;
4138 screen->state.glt = NULL;
4139 screen->state.grt = NULL;
4140 screen->state.auto_wrap = 0;
4141 screen->state.origin_mode = 0;
4143 screen->saved = screen->state;
4144 screen->saved.cursor_x = 0;
4145 screen->saved.cursor_y = 0;
4147 screen->page = screen->page_main;
4148 screen->history = screen->history_main;
4149 screen->flags = TERM_FLAG_7BIT_MODE;
4150 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
4152 for (i = 0; i < screen->page->width; i += 8)
4153 screen->tabs[i / 8] = 0x1;
4155 term_page_set_scroll_region(screen->page_main, 0, screen->page->height);
4156 term_page_set_scroll_region(screen->page_alt, 0, screen->page->height);
4159 void term_screen_hard_reset(term_screen *screen) {
4162 term_screen_soft_reset(screen);
4164 screen->state.cursor_x = 0;
4165 screen->state.cursor_y = 0;
4166 term_page_erase(screen->page_main, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false);
4167 term_page_erase(screen->page_alt, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false);
4170 int term_screen_set_answerback(term_screen *screen, const char *answerback) {
4173 assert_return(screen, -EINVAL);
4176 t = strdup(answerback);
4181 free(screen->answerback);
4182 screen->answerback = t;
4187 int term_screen_draw(term_screen *screen,
4188 int (*draw_fn) (term_screen *screen,
4192 const term_attr *attr,
4195 unsigned int ch_width),
4198 uint64_t cell_age, line_age, age = 0;
4199 term_charbuf_t ch_buf;
4200 const uint32_t *ch_str;
4201 unsigned int i, j, cw;
4214 page = screen->page;
4216 for (j = 0; j < page->height; ++j) {
4217 line = page->lines[j];
4218 line_age = MAX(line->age, page->age);
4220 for (i = 0; i < page->width; ++i) {
4223 cell = &line->cells[i];
4224 cell_age = MAX(cell->age, line_age);
4226 if (age != 0 && cell_age <= age)
4229 ch_str = term_char_resolve(cell->ch, &ch_n, &ch_buf);
4231 /* Character-width of 0 is used for cleared cells.
4232 * Always treat this as single-cell character, so
4233 * renderers can assume ch_width is set properpy. */
4234 cw = MAX(cell->cwidth, 1U);
4237 if (i == screen->state.cursor_x && j == screen->state.cursor_y &&
4238 !(screen->flags & TERM_FLAG_HIDE_CURSOR))
4255 *fb_age = screen->age;