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
51 #include "term-internal.h"
54 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) {
55 _cleanup_(term_screen_unrefp) term_screen *screen = NULL;
58 assert_return(out, -EINVAL);
60 screen = new0(term_screen, 1);
66 screen->write_fn = write_fn;
67 screen->write_fn_data = write_fn_data;
68 screen->cmd_fn = cmd_fn;
69 screen->cmd_fn_data = cmd_fn_data;
70 screen->flags = TERM_FLAG_7BIT_MODE;
71 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
72 screen->gl = &screen->g0;
73 screen->gr = &screen->g1;
74 screen->g0 = &term_unicode_lower;
75 screen->g1 = &term_unicode_upper;
76 screen->g2 = &term_unicode_lower;
77 screen->g3 = &term_unicode_upper;
79 screen->saved.cursor_x = 0;
80 screen->saved.cursor_y = 0;
81 screen->saved.attr = screen->attr;
82 screen->saved.gl = screen->gl;
83 screen->saved.gr = screen->gr;
85 r = term_page_new(&screen->page_main);
89 r = term_page_new(&screen->page_alt);
93 r = term_parser_new(&screen->parser, false);
97 r = term_history_new(&screen->history_main);
101 screen->page = screen->page_main;
102 screen->history = screen->history_main;
109 term_screen *term_screen_ref(term_screen *screen) {
113 assert_return(screen->ref > 0, NULL);
119 term_screen *term_screen_unref(term_screen *screen) {
123 assert_return(screen->ref > 0, NULL);
128 free(screen->answerback);
130 term_history_free(screen->history_main);
131 term_page_free(screen->page_alt);
132 term_page_free(screen->page_main);
133 term_parser_free(screen->parser);
141 * Unfortunately, 7bit/8bit compat mode requires us to send C1 controls encoded
142 * as 7bit if asked by the application. This is really used in the wild, so we
143 * cannot fall back to "always 7bit".
144 * screen_write() is the underlying backend which forwards any writes to the
145 * users's callback. It's the users responsibility to buffer these and write
146 * them out once their call to term_screen_feed_*() returns.
147 * The SEQ_WRITE() and SEQ_WRITE_KEY() macros allow constructing C0/C1 sequences
148 * directly in the code-base without requiring any intermediate buffer during
153 #define C1_CSI "\x9b"
155 #define SEQ(_screen, _prefix_esc, _c0, _c1, _seq) \
156 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
157 ((_prefix_esc) ? ("\e" _c0 _seq) : (_c0 _seq)) : \
158 ((_prefix_esc) ? ("\e" _c1 _seq) : (_c1 _seq)))
160 #define SEQ_SIZE(_screen, _prefix_esc, _c0, _c1, _seq) \
161 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
162 ((_prefix_esc) ? sizeof("\e" _c0 _seq) : sizeof(_c0 _seq)) : \
163 ((_prefix_esc) ? sizeof("\e" _c1 _seq) : sizeof(_c1 _seq)))
165 #define SEQ_WRITE_KEY(_screen, _prefix_esc, _c0, _c1, _seq) \
166 screen_write((_screen), \
167 SEQ((_screen), (_prefix_esc), \
169 SEQ_SIZE((_screen), (_prefix_esc), \
172 #define SEQ_WRITE(_screen, _c0, _c1, _seq) \
173 SEQ_WRITE_KEY((_screen), false, _c0, _c1, _seq)
175 static int screen_write(term_screen *screen, const void *buf, size_t len) {
176 if (len < 1 || !screen->write_fn)
179 return screen->write_fn(screen, screen->write_fn_data, buf, len);
184 * Some commands cannot be handled by the screen-layer directly. Those are
185 * forwarded to the command-handler of the caller. This is rarely used and can
186 * safely be set to NULL.
189 static int screen_forward(term_screen *screen, unsigned int cmd, const term_seq *seq) {
193 return screen->cmd_fn(screen, screen->cmd_fn_data, cmd, seq);
198 * These helpers implement common-operations like cursor-handler and more, which
199 * are used by several command dispatchers.
202 static unsigned int screen_clamp_x(term_screen *screen, unsigned int x) {
203 if (x >= screen->page->width)
204 return (screen->page->width > 0) ? screen->page->width - 1 : 0;
209 static unsigned int screen_clamp_y(term_screen *screen, unsigned int y) {
210 if (y >= screen->page->height)
211 return (screen->page->height > 0) ? screen->page->height - 1 : 0;
216 static bool screen_tab_is_set(term_screen *screen, unsigned int pos) {
217 if (pos >= screen->page->width)
220 return screen->tabs[pos / 8] & (1 << (pos % 8));
223 static inline void screen_age_cursor(term_screen *screen) {
226 cell = term_page_get_cell(screen->page, screen->cursor_x, screen->cursor_y);
228 cell->age = screen->age;
231 static void screen_cursor_clear_wrap(term_screen *screen) {
232 screen->flags &= ~TERM_FLAG_PENDING_WRAP;
235 static void screen_cursor_set(term_screen *screen, unsigned int x, unsigned int y) {
236 x = screen_clamp_x(screen, x);
237 y = screen_clamp_y(screen, y);
239 if (x == screen->cursor_x && y == screen->cursor_y)
242 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
243 screen_age_cursor(screen);
245 screen->cursor_x = x;
246 screen->cursor_y = y;
248 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
249 screen_age_cursor(screen);
252 static void screen_cursor_set_rel(term_screen *screen, unsigned int x, unsigned int y) {
253 if (screen->flags & TERM_FLAG_ORIGIN_MODE) {
254 x = screen_clamp_x(screen, x);
255 y = screen_clamp_x(screen, y) + screen->page->scroll_idx;
257 if (y >= screen->page->scroll_idx + screen->page->scroll_num) {
258 y = screen->page->scroll_idx + screen->page->scroll_num;
259 if (screen->page->scroll_num > 0)
264 screen_cursor_set(screen, x, y);
267 static void screen_cursor_left(term_screen *screen, unsigned int num) {
268 if (num > screen->cursor_x)
269 num = screen->cursor_x;
271 screen_cursor_set(screen, screen->cursor_x - num, screen->cursor_y);
274 static void screen_cursor_left_tab(term_screen *screen, unsigned int num) {
277 i = screen->cursor_x;
278 while (i > 0 && num > 0) {
279 if (screen_tab_is_set(screen, --i))
283 screen_cursor_set(screen, i, screen->cursor_y);
286 static void screen_cursor_right(term_screen *screen, unsigned int num) {
287 if (num > screen->page->width)
288 num = screen->page->width;
290 screen_cursor_set(screen, screen->cursor_x + num, screen->cursor_y);
293 static void screen_cursor_right_tab(term_screen *screen, unsigned int num) {
296 i = screen->cursor_x;
297 while (i + 1 < screen->page->width && num > 0) {
298 if (screen_tab_is_set(screen, ++i))
302 screen_cursor_set(screen, i, screen->cursor_y);
305 static void screen_cursor_up(term_screen *screen, unsigned int num, bool scroll) {
308 if (screen->cursor_y < screen->page->scroll_idx) {
309 if (num > screen->cursor_y)
310 num = screen->cursor_y;
312 screen_cursor_set(screen, screen->cursor_x, screen->cursor_y - num);
314 max = screen->cursor_y - screen->page->scroll_idx;
319 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
320 screen_age_cursor(screen);
323 term_page_scroll_down(screen->page, num - max, &screen->attr, screen->age, NULL);
325 screen->cursor_y = screen->page->scroll_idx;
327 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
328 screen_age_cursor(screen);
330 screen_cursor_set(screen, screen->cursor_x, screen->cursor_y - num);
335 static void screen_cursor_down(term_screen *screen, unsigned int num, bool scroll) {
338 if (screen->cursor_y >= screen->page->scroll_idx + screen->page->scroll_num) {
339 if (num > screen->page->height)
340 num = screen->page->height;
342 screen_cursor_set(screen, screen->cursor_x, screen->cursor_y - num);
344 max = screen->page->scroll_idx + screen->page->scroll_num - 1 - screen->cursor_y;
349 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
350 screen_age_cursor(screen);
353 term_page_scroll_up(screen->page, num - max, &screen->attr, screen->age, screen->history);
355 screen->cursor_y = screen->page->scroll_idx + screen->page->scroll_num - 1;
357 if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
358 screen_age_cursor(screen);
360 screen_cursor_set(screen, screen->cursor_x, screen->cursor_y + num);
365 static inline void set_reset(term_screen *screen, unsigned int flag, bool set) {
367 screen->flags |= flag;
369 screen->flags &= ~flag;
372 static void screen_mode_change(term_screen *screen, unsigned int mode, bool dec, bool set) {
377 * DECCKM: cursor-keys
380 set_reset(screen, TERM_FLAG_CURSOR_KEYS, set);
390 set_reset(screen, TERM_FLAG_ORIGIN_MODE, set);
397 * DECAWN: auto-wrap mode
400 set_reset(screen, TERM_FLAG_AUTO_WRAP, set);
407 * LNM: line-feed/new-line mode
410 set_reset(screen, TERM_FLAG_NEWLINE_MODE, set);
417 * DECTCEM: text-cursor-enable
420 set_reset(screen, TERM_FLAG_HIDE_CURSOR, !set);
427 /* map a character according to current GL and GR maps */
428 static uint32_t screen_map(term_screen *screen, uint32_t val) {
431 /* 32 and 127 always map to identity. 160 and 255 map to identity iff a
432 * 96 character set is loaded into GR. Values above 255 always map to
437 nval = (**screen->glt)[val - 32];
440 nval = (**screen->gl)[val - 32];
445 nval = (**screen->grt)[val - 160];
448 nval = (**screen->gr)[val - 160];
453 return (nval == -1U) ? val : nval;
458 * This is the unofficial documentation of all the TERM_CMD_* definitions. Each
459 * handled command has a separate function with an extensive comment on the
460 * semantics of the command.
461 * Note that many semantics are unknown and need to be verified. This is mostly
462 * about error-handling, though. Applications rarely rely on those features.
465 static int screen_DA1(term_screen *screen, const term_seq *seq);
466 static int screen_LF(term_screen *screen, const term_seq *seq);
468 static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) {
469 term_char_t ch = TERM_CHAR_NULL;
472 if (screen->cursor_x + 1 == screen->page->width
473 && screen->flags & TERM_FLAG_PENDING_WRAP
474 && screen->flags & TERM_FLAG_AUTO_WRAP) {
475 screen_cursor_down(screen, 1, true);
476 screen_cursor_set(screen, 0, screen->cursor_y);
479 screen_cursor_clear_wrap(screen);
481 c = screen_map(screen, seq->terminator);
482 ch = term_char_merge(ch, screen_map(screen, c));
483 term_page_write(screen->page, screen->cursor_x, screen->cursor_y, ch, 1, &screen->attr, screen->age, false);
485 if (screen->cursor_x + 1 == screen->page->width)
486 screen->flags |= TERM_FLAG_PENDING_WRAP;
488 screen_cursor_right(screen, 1);
493 static int screen_BEL(term_screen *screen, const term_seq *seq) {
495 * BEL - sound bell tone
496 * This command should trigger an acoustic bell. Usually, this is
497 * forwarded directly to the pcspkr. However, bells have become quite
498 * uncommon and annoying, so we're not implementing them here. Instead,
499 * it's one of the commands we forward to the caller.
502 return screen_forward(screen, TERM_CMD_BEL, seq);
505 static int screen_BS(term_screen *screen, const term_seq *seq) {
508 * Move cursor one cell to the left. If already at the left margin,
512 screen_cursor_clear_wrap(screen);
513 screen_cursor_left(screen, 1);
517 static int screen_CBT(term_screen *screen, const term_seq *seq) {
519 * CBT - cursor-backward-tabulation
520 * Move the cursor @args[0] tabs backwards (to the left). The
521 * current cursor cell, in case it's a tab, is not counted.
522 * Furthermore, the cursor cannot be moved beyond position 0 and
523 * it will stop there.
529 unsigned int num = 1;
531 if (seq->args[0] > 0)
534 screen_cursor_clear_wrap(screen);
535 screen_cursor_left_tab(screen, num);
540 static int screen_CHA(term_screen *screen, const term_seq *seq) {
542 * CHA - cursor-horizontal-absolute
543 * Move the cursor to position @args[0] in the current line. The
544 * cursor cannot be moved beyond the rightmost cell and will stop
551 unsigned int pos = 1;
553 if (seq->args[0] > 0)
556 screen_cursor_clear_wrap(screen);
557 screen_cursor_set(screen, pos - 1, screen->cursor_y);
562 static int screen_CHT(term_screen *screen, const term_seq *seq) {
564 * CHT - cursor-horizontal-forward-tabulation
565 * Move the cursor @args[0] tabs forward (to the right). The
566 * current cursor cell, in case it's a tab, is not counted.
567 * Furthermore, the cursor cannot be moved beyond the rightmost cell
568 * and will stop there.
574 unsigned int num = 1;
576 if (seq->args[0] > 0)
579 screen_cursor_clear_wrap(screen);
580 screen_cursor_right_tab(screen, num);
585 static int screen_CNL(term_screen *screen, const term_seq *seq) {
587 * CNL - cursor-next-line
588 * Move the cursor @args[0] lines down.
590 * TODO: Does this stop at the bottom or cause a scroll-up?
596 unsigned int num = 1;
598 if (seq->args[0] > 0)
601 screen_cursor_clear_wrap(screen);
602 screen_cursor_down(screen, num, false);
607 static int screen_CPL(term_screen *screen, const term_seq *seq) {
609 * CPL - cursor-preceding-line
610 * Move the cursor @args[0] lines up.
612 * TODO: Does this stop at the top or cause a scroll-up?
618 unsigned int num = 1;
620 if (seq->args[0] > 0)
623 screen_cursor_clear_wrap(screen);
624 screen_cursor_up(screen, num, false);
629 static int screen_CR(term_screen *screen, const term_seq *seq) {
631 * CR - carriage-return
632 * Move the cursor to the left margin on the current line.
635 screen_cursor_clear_wrap(screen);
636 screen_cursor_set(screen, 0, screen->cursor_y);
641 static int screen_CUB(term_screen *screen, const term_seq *seq) {
643 * CUB - cursor-backward
644 * Move the cursor @args[0] positions to the left. The cursor stops
645 * at the left-most position.
651 unsigned int num = 1;
653 if (seq->args[0] > 0)
656 screen_cursor_clear_wrap(screen);
657 screen_cursor_left(screen, num);
662 static int screen_CUD(term_screen *screen, const term_seq *seq) {
665 * Move the cursor @args[0] positions down. The cursor stops at the
666 * bottom margin. If it was already moved further, it stops at the
673 unsigned int num = 1;
675 if (seq->args[0] > 0)
678 screen_cursor_clear_wrap(screen);
679 screen_cursor_down(screen, num, false);
684 static int screen_CUF(term_screen *screen, const term_seq *seq) {
686 * CUF -cursor-forward
687 * Move the cursor @args[0] positions to the right. The cursor stops
688 * at the right-most position.
694 unsigned int num = 1;
696 if (seq->args[0] > 0)
699 screen_cursor_clear_wrap(screen);
700 screen_cursor_right(screen, num);
705 static int screen_CUP(term_screen *screen, const term_seq *seq) {
707 * CUP - cursor-position
708 * Moves the cursor to position @args[1] x @args[0]. If either is 0, it
709 * is treated as 1. The positions are subject to the origin-mode and
710 * clamped to the addressable with/height.
717 unsigned int x = 1, y = 1;
719 if (seq->args[0] > 0)
721 if (seq->args[1] > 0)
724 screen_cursor_clear_wrap(screen);
725 screen_cursor_set_rel(screen, x - 1, y - 1);
730 static int screen_CUU(term_screen *screen, const term_seq *seq) {
733 * Move the cursor @args[0] positions up. The cursor stops at the
734 * top margin. If it was already moved further, it stops at the
742 unsigned int num = 1;
744 if (seq->args[0] > 0)
747 screen_cursor_clear_wrap(screen);
748 screen_cursor_up(screen, num, false);
753 static int screen_DA1(term_screen *screen, const term_seq *seq) {
755 * DA1 - primary-device-attributes
756 * The primary DA asks for basic terminal features. We simply return
757 * a hard-coded list of features we implement.
758 * Note that the primary DA asks for supported features, not currently
761 * The terminal's answer is:
763 * The first argument, 64, is fixed and denotes a VT420, the last
764 * DEC-term that extended this number.
765 * All following arguments denote supported features. Note
766 * that at most 15 features can be sent (max CSI args). It is safe to
767 * send more, but clients might not be able to parse them. This is a
768 * client's problem and we shouldn't care. There is no other way to
769 * send those feature lists, so we have to extend them beyond 15 in
774 * The 132 column mode is supported by the terminal.
776 * A priner-port is supported and can be addressed via
779 * Support for ReGIS graphics is available. The ReGIS routines
780 * provide the "remote graphics instruction set" and allow basic
783 * Support of Sixel graphics is available. This provides access
784 * to the sixel bitmap routines.
786 * The terminal supports DECSCA and related selective-erase
787 * functions. This allows to protect specific cells from being
788 * erased, if specified.
789 * 7: soft character set (DRCS)
791 * 8: user-defined keys (UDKs)
793 * 9: national-replacement character sets (NRCS)
794 * National-replacement character-sets are available.
795 * 12: Yugoslavian (SCS)
797 * 15: technical character set
798 * The DEC technical-character-set is available.
799 * 18: windowing capability
801 * 21: horizontal scrolling
809 * 29: ANSI text locator
811 * 42: ISO Latin-2 character set
817 * 46: ASCII emulation
821 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "?64;1;6;9;15c");
824 static int screen_DA2(term_screen *screen, const term_seq *seq) {
826 * DA2 - secondary-device-attributes
827 * The secondary DA asks for the terminal-ID, firmware versions and
828 * other non-primary attributes. All these values are
829 * informational-only and should not be used by the host to detect
832 * The terminal's response is:
833 * ^[ > 61 ; FIRMWARE ; KEYBOARD c
834 * whereas 65 is fixed for VT525 terminals, the last terminal-line that
835 * increased this number. FIRMWARE is the firmware
836 * version encoded as major/minor (20 == 2.0) and KEYBOARD is 0 for STD
837 * keyboard and 1 for PC keyboards.
839 * We replace the firmware-version with the systemd-version so clients
840 * can decode it again.
843 return SEQ_WRITE(screen, C0_CSI, C1_CSI, ">65;" PACKAGE_VERSION ";1c");
846 static int screen_DA3(term_screen *screen, const term_seq *seq) {
848 * DA3 - tertiary-device-attributes
849 * The tertiary DA is used to query the terminal-ID.
851 * The terminal's response is:
852 * ^P ! | XX AA BB CC ^\
853 * whereas all four parameters are hexadecimal-encoded pairs. XX
854 * denotes the manufacturing site, AA BB CC is the terminal's ID.
857 /* we do not support tertiary DAs */
861 static int screen_DC1(term_screen *screen, const term_seq *seq) {
863 * DC1 - device-control-1 or XON
864 * This clears any previous XOFF and resumes terminal-transmission.
867 /* we do not support XON */
871 static int screen_DC3(term_screen *screen, const term_seq *seq) {
873 * DC3 - device-control-3 or XOFF
874 * Stops terminal transmission. No further characters are sent until
875 * an XON is received.
878 /* we do not support XOFF */
882 static int screen_DCH(term_screen *screen, const term_seq *seq) {
884 * DCH - delete-character
885 * This deletes @argv[0] characters at the current cursor position. As
886 * characters are deleted, the remaining characters between the cursor
887 * and right margin move to the left. Character attributes move with the
888 * characters. The terminal adds blank spaces with no visual character
889 * attributes at the right margin. DCH has no effect outside the
896 unsigned int num = 1;
898 if (seq->args[0] > 0)
901 screen_cursor_clear_wrap(screen);
902 term_page_delete_cells(screen->page, screen->cursor_x, screen->cursor_y, num, &screen->attr, screen->age);
907 static int screen_DECALN(term_screen *screen, const term_seq *seq) {
909 * DECALN - screen-alignment-pattern
911 * Probably not worth implementing.
917 static int screen_DECANM(term_screen *screen, const term_seq *seq) {
920 * Set the terminal into VT52 compatibility mode. Control sequences
921 * overlap with regular sequences so we have to detect them early before
924 * Probably not worth implementing.
930 static int screen_DECBI(term_screen *screen, const term_seq *seq) {
933 * This control function moves the cursor backward one column. If the
934 * cursor is at the left margin, then all screen data within the margin
935 * moves one column to the right. The column that shifted past the right
937 * DECBI adds a new column at the left margin with no visual attributes.
938 * DECBI does not affect the margins. If the cursor is beyond the
939 * left-margin at the left border, then the terminal ignores DECBI.
941 * Probably not worth implementing.
947 static int screen_DECCARA(term_screen *screen, const term_seq *seq) {
949 * DECCARA - change-attributes-in-rectangular-area
951 * Probably not worth implementing.
957 static int screen_DECCRA(term_screen *screen, const term_seq *seq) {
959 * DECCRA - copy-rectangular-area
961 * Probably not worth implementing.
967 static int screen_DECDC(term_screen *screen, const term_seq *seq) {
969 * DECDC - delete-column
971 * Probably not worth implementing.
977 static int screen_DECDHL_BH(term_screen *screen, const term_seq *seq) {
979 * DECDHL_BH - double-width-double-height-line: bottom half
981 * Probably not worth implementing.
987 static int screen_DECDHL_TH(term_screen *screen, const term_seq *seq) {
989 * DECDHL_TH - double-width-double-height-line: top half
991 * Probably not worth implementing.
997 static int screen_DECDWL(term_screen *screen, const term_seq *seq) {
999 * DECDWL - double-width-single-height-line
1001 * Probably not worth implementing.
1007 static int screen_DECEFR(term_screen *screen, const term_seq *seq) {
1009 * DECEFR - enable-filter-rectangle
1010 * Defines the coordinates of a filter rectangle (top, left, bottom,
1011 * right as @args[0] to @args[3]) and activates it.
1012 * Anytime the locator is detected outside of the filter rectangle, an
1013 * outside rectangle event is generated and the rectangle is disabled.
1014 * Filter rectangles are always treated as "one-shot" events. Any
1015 * parameters that are omitted default to the current locator position.
1016 * If all parameters are omitted, any locator motion will be reported.
1017 * DECELR always cancels any prevous rectangle definition.
1019 * The locator is usually associated with the mouse-cursor, but based
1020 * on cells instead of pixels. See DECELR how to initialize and enable
1021 * it. DECELR can also enable pixel-mode instead of cell-mode.
1029 static int screen_DECELF(term_screen *screen, const term_seq *seq) {
1031 * DECELF - enable-local-functions
1033 * Probably not worth implementing.
1039 static int screen_DECELR(term_screen *screen, const term_seq *seq) {
1041 * DECELR - enable-locator-reporting
1042 * This changes the locator-reporting mode. @args[0] specifies the mode
1043 * to set, 0 disables locator-reporting, 1 enables it continuously, 2
1044 * enables it for a single report. @args[1] specifies the
1045 * precision-mode. 0 and 2 set the reporting to cell-precision, 1 sets
1058 static int screen_DECERA(term_screen *screen, const term_seq *seq) {
1060 * DECERA - erase-rectangular-area
1062 * Probably not worth implementing.
1068 static int screen_DECFI(term_screen *screen, const term_seq *seq) {
1070 * DECFI - forward-index
1071 * This control function moves the cursor forward one column. If the
1072 * cursor is at the right margin, then all screen data within the
1073 * margins moves one column to the left. The column shifted past the
1074 * left margin is lost.
1075 * DECFI adds a new column at the right margin, with no visual
1076 * attributes. DECFI does not affect margins. If the cursor is beyond
1077 * the right margin at the border of the page when the terminal
1078 * receives DECFI, then the terminal ignores DECFI.
1080 * Probably not worth implementing.
1086 static int screen_DECFRA(term_screen *screen, const term_seq *seq) {
1088 * DECFRA - fill-rectangular-area
1090 * Probably not worth implementing.
1096 static int screen_DECIC(term_screen *screen, const term_seq *seq) {
1098 * DECIC - insert-column
1100 * Probably not worth implementing.
1106 static int screen_DECID(term_screen *screen, const term_seq *seq) {
1108 * DECID - return-terminal-id
1109 * This is an obsolete form of TERM_CMD_DA1.
1112 return screen_DA1(screen, seq);
1115 static int screen_DECINVM(term_screen *screen, const term_seq *seq) {
1117 * DECINVM - invoke-macro
1119 * Probably not worth implementing.
1125 static int screen_DECKBD(term_screen *screen, const term_seq *seq) {
1127 * DECKBD - keyboard-language-selection
1129 * Probably not worth implementing.
1135 static int screen_DECKPAM(term_screen *screen, const term_seq *seq) {
1137 * DECKPAM - keypad-application-mode
1138 * Enables the keypad-application mode. If enabled, the keypad sends
1139 * special characters instead of the printed characters. This way,
1140 * applications can detect whether a numeric key was pressed on the
1141 * top-row or on the keypad.
1142 * Default is keypad-numeric-mode.
1145 screen->flags |= TERM_FLAG_KEYPAD_MODE;
1150 static int screen_DECKPNM(term_screen *screen, const term_seq *seq) {
1152 * DECKPNM - keypad-numeric-mode
1153 * This disables the keypad-application-mode (DECKPAM) and returns to
1154 * the keypad-numeric-mode. Keypresses on the keypad generate the same
1155 * sequences as corresponding keypresses on the main keyboard.
1156 * Default is keypad-numeric-mode.
1159 screen->flags &= ~TERM_FLAG_KEYPAD_MODE;
1164 static int screen_DECLFKC(term_screen *screen, const term_seq *seq) {
1166 * DECLFKC - local-function-key-control
1168 * Probably not worth implementing.
1174 static int screen_DECLL(term_screen *screen, const term_seq *seq) {
1178 * Probably not worth implementing.
1184 static int screen_DECLTOD(term_screen *screen, const term_seq *seq) {
1186 * DECLTOD - load-time-of-day
1188 * Probably not worth implementing.
1194 static int screen_DECPCTERM(term_screen *screen, const term_seq *seq) {
1196 * DECPCTERM - pcterm-mode
1197 * This enters/exits the PCTerm mode. Default mode is VT-mode. It can
1198 * also select parameters for scancode/keycode mappings in SCO mode.
1200 * Definitely not worth implementing. Lets kill PCTerm/SCO modes!
1206 static int screen_DECPKA(term_screen *screen, const term_seq *seq) {
1208 * DECPKA - program-key-action
1210 * Probably not worth implementing.
1216 static int screen_DECPKFMR(term_screen *screen, const term_seq *seq) {
1218 * DECPKFMR - program-key-free-memory-report
1220 * Probably not worth implementing.
1226 static int screen_DECRARA(term_screen *screen, const term_seq *seq) {
1228 * DECRARA - reverse-attributes-in-rectangular-area
1230 * Probably not worth implementing.
1236 static int screen_DECRC(term_screen *screen, const term_seq *seq) {
1238 * DECRC - restore-cursor
1239 * Restores the terminal to the state saved by the save cursor (DECSC)
1240 * function. This includes more than just the cursor-position.
1242 * If nothing was saved by DECSC, then DECRC performs the following
1244 * * Moves the cursor to the home position (upper left of screen).
1245 * * Resets origin mode (DECOM).
1246 * * Turns all character attributes off (normal setting).
1247 * * Maps the ASCII character set into GL, and the DEC Supplemental
1248 * Graphic set into GR.
1250 * The terminal maintains a separate DECSC buffer for the main display
1251 * and the status line. This feature lets you save a separate operating
1252 * state for the main display and the status line.
1255 screen->attr = screen->saved.attr;
1256 screen->gl = screen->saved.gl;
1257 screen->gr = screen->saved.gr;
1258 screen->glt = screen->saved.glt;
1259 screen->grt = screen->saved.grt;
1260 set_reset(screen, TERM_FLAG_AUTO_WRAP, screen->flags & TERM_FLAG_AUTO_WRAP);
1261 set_reset(screen, TERM_FLAG_ORIGIN_MODE, screen->flags & TERM_FLAG_ORIGIN_MODE);
1262 screen_cursor_set(screen, screen->saved.cursor_x, screen->saved.cursor_y);
1267 static int screen_DECREQTPARM(term_screen *screen, const term_seq *seq) {
1269 * DECREQTPARM - request-terminal-parameters
1270 * The sequence DECREPTPARM is sent by the terminal controller to notify
1271 * the host of the status of selected terminal parameters. The status
1272 * sequence may be sent when requested by the host or at the terminal's
1273 * discretion. DECREPTPARM is sent upon receipt of a DECREQTPARM.
1275 * If @args[0] is 0, this marks a request and the terminal is allowed
1276 * to send DECREPTPARM messages without request. If it is 1, the same
1277 * applies but the terminal should no longer send DECREPTPARM
1279 * 2 and 3 mark a report, but 3 is only used if the terminal answers as
1280 * an explicit request with @args[0] == 1.
1282 * The other arguments are ignored in requests, but have the following
1283 * meaning in responses:
1284 * args[1]: 1=no-parity-set 4=parity-set-and-odd 5=parity-set-and-even
1285 * args[2]: 1=8bits-per-char 2=7bits-per-char
1286 * args[3]: transmission-speed
1287 * args[4]: receive-speed
1288 * args[5]: 1=bit-rate-multiplier-is-16
1289 * args[6]: This value communicates the four switch values in block 5
1290 * of SETUP B, which are only visible to the user when an STP
1291 * option is installed. These bits may be assigned for an STP
1292 * device. The four bits are a decimal-encoded binary number.
1293 * Value between 0-15.
1295 * The transmission/receive speeds have mappings for number => bits/s
1296 * which are quite weird. Examples are: 96->3600, 112->9600, 120->19200
1302 if (seq->n_args < 1 || seq->args[0] == 0) {
1303 screen->flags &= ~TERM_FLAG_INHIBIT_TPARM;
1304 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "2;1;1;120;120;1;0x");
1305 } else if (seq->args[0] == 1) {
1306 screen->flags |= TERM_FLAG_INHIBIT_TPARM;
1307 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "3;1;1;120;120;1;0x");
1313 static int screen_DECRPKT(term_screen *screen, const term_seq *seq) {
1315 * DECRPKT - report-key-type
1316 * Response to DECRQKT, we can safely ignore it as we're the one sending
1323 static int screen_DECRQCRA(term_screen *screen, const term_seq *seq) {
1325 * DECRQCRA - request-checksum-of-rectangular-area
1327 * Probably not worth implementing.
1333 static int screen_DECRQDE(term_screen *screen, const term_seq *seq) {
1335 * DECRQDE - request-display-extent
1337 * Probably not worth implementing.
1343 static int screen_DECRQKT(term_screen *screen, const term_seq *seq) {
1345 * DECRQKT - request-key-type
1347 * Probably not worth implementing.
1353 static int screen_DECRQLP(term_screen *screen, const term_seq *seq) {
1355 * DECRQLP - request-locator-position
1356 * See DECELR for locator-information.
1358 * TODO: document and implement
1364 static int screen_DECRQM_ANSI(term_screen *screen, const term_seq *seq) {
1366 * DECRQM_ANSI - request-mode-ansi
1367 * The host sends this control function to find out if a particular mode
1368 * is set or reset. The terminal responds with a report mode function.
1369 * @args[0] contains the mode to query.
1371 * Response is DECRPM with the first argument set to the mode that was
1372 * queried, second argument is 0 if mode is invalid, 1 if mode is set,
1373 * 2 if mode is not set (reset), 3 if mode is permanently set and 4 if
1374 * mode is permanently not set (reset):
1375 * ANSI: ^[ MODE ; VALUE $ y
1376 * DEC: ^[ ? MODE ; VALUE $ y
1384 static int screen_DECRQM_DEC(term_screen *screen, const term_seq *seq) {
1386 * DECRQM_DEC - request-mode-dec
1387 * Same as DECRQM_ANSI but for DEC modes.
1395 static int screen_DECRQPKFM(term_screen *screen, const term_seq *seq) {
1397 * DECRQPKFM - request-program-key-free-memory
1399 * Probably not worth implementing.
1405 static int screen_DECRQPSR(term_screen *screen, const term_seq *seq) {
1407 * DECRQPSR - request-presentation-state-report
1409 * Probably not worth implementing.
1415 static int screen_DECRQTSR(term_screen *screen, const term_seq *seq) {
1417 * DECRQTSR - request-terminal-state-report
1419 * Probably not worth implementing.
1425 static int screen_DECRQUPSS(term_screen *screen, const term_seq *seq) {
1427 * DECRQUPSS - request-user-preferred-supplemental-set
1429 * Probably not worth implementing.
1435 static int screen_DECSACE(term_screen *screen, const term_seq *seq) {
1437 * DECSACE - select-attribute-change-extent
1439 * Probably not worth implementing.
1445 static int screen_DECSASD(term_screen *screen, const term_seq *seq) {
1447 * DECSASD - select-active-status-display
1449 * Probably not worth implementing.
1455 static int screen_DECSC(term_screen *screen, const term_seq *seq) {
1457 * DECSC - save-cursor
1458 * Save cursor and terminal state so it can be restored later on.
1459 * Saves the following items in the terminal's memory:
1461 * * Character attributes set by the SGR command
1462 * * Character sets (G0, G1, G2, or G3) currently in GL and GR
1463 * * Wrap flag (autowrap or no autowrap)
1464 * * State of origin mode (DECOM)
1465 * * Selective erase attribute
1466 * * Any single shift 2 (SS2) or single shift 3 (SS3) functions sent
1469 screen->saved.cursor_x = screen->cursor_x;
1470 screen->saved.cursor_y = screen->cursor_y;
1471 screen->saved.attr = screen->attr;
1472 screen->saved.gl = screen->gl;
1473 screen->saved.gr = screen->gr;
1474 screen->saved.glt = screen->glt;
1475 screen->saved.grt = screen->grt;
1476 screen->saved.flags = screen->flags & (TERM_FLAG_AUTO_WRAP
1477 | TERM_FLAG_ORIGIN_MODE);
1482 static int screen_DECSCA(term_screen *screen, const term_seq *seq) {
1484 * DECSCA - select-character-protection-attribute
1485 * Defines the characters that come after it as erasable or not erasable
1486 * from the screen. The selective erase control functions (DECSED and
1487 * DECSEL) can only erase characters defined as erasable.
1489 * @args[0] specifies the new mode. 0 and 2 mark any following character
1490 * as erasable, 1 marks it as not erasable.
1496 unsigned int mode = 0;
1498 if (seq->args[0] > 0)
1499 mode = seq->args[0];
1504 screen->attr.protect = 0;
1507 screen->attr.protect = 1;
1514 static int screen_DECSCL(term_screen *screen, const term_seq *seq) {
1516 * DECSCL - select-conformance-level
1517 * Select the terminal's operating level. The factory default is
1518 * level 4 (VT Level 4 mode, 7-bit controls).
1519 * When you change the conformance level, the terminal performs a hard
1522 * @args[0] defines the conformance-level, valid values are:
1523 * 61: Level 1 (VT100)
1524 * 62: Level 2 (VT200)
1525 * 63: Level 3 (VT300)
1526 * 64: Level 4 (VT400)
1527 * @args[1] defines the 8bit-mode, valid values are:
1530 * 2: 8-bit controls (same as 0)
1532 * If @args[0] is 61, then @args[1] is ignored and 7bit controls are
1540 unsigned int level = 64, bit = 0;
1542 if (seq->n_args > 0) {
1543 level = seq->args[0];
1544 if (seq->n_args > 1)
1548 term_screen_hard_reset(screen);
1552 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT100;
1553 screen->flags |= TERM_FLAG_7BIT_MODE;
1556 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
1558 screen->flags |= TERM_FLAG_7BIT_MODE;
1560 screen->flags &= ~TERM_FLAG_7BIT_MODE;
1567 static int screen_DECSCP(term_screen *screen, const term_seq *seq) {
1569 * DECSCP - select-communication-port
1571 * Probably not worth implementing.
1577 static int screen_DECSCPP(term_screen *screen, const term_seq *seq) {
1579 * DECSCPP - select-columns-per-page
1580 * Select columns per page. The number of rows is unaffected by this.
1581 * @args[0] selectes the number of columns (width), DEC only defines 80
1582 * and 132, but we allow any integer here. 0 is equivalent to 80.
1583 * Page content is *not* cleared and the cursor is left untouched.
1584 * However, if the page is reduced in width and the cursor would be
1585 * outside the visible region, it's set to the right border. Newly added
1586 * cells are cleared. No data is retained outside the visible region.
1597 static int screen_DECSCS(term_screen *screen, const term_seq *seq) {
1599 * DECSCS - select-communication-speed
1601 * Probably not worth implementing.
1607 static int screen_DECSCUSR(term_screen *screen, const term_seq *seq) {
1609 * DECSCUSR - set-cursor-style
1610 * This changes the style of the cursor. @args[0] can be one of:
1611 * 0, 1: blinking block
1613 * 3: blinking underline
1614 * 4: steady underline
1615 * Changing this setting does _not_ affect the cursor visibility itself.
1616 * Use DECTCEM for that.
1627 static int screen_DECSDDT(term_screen *screen, const term_seq *seq) {
1629 * DECSDDT - select-disconnect-delay-time
1631 * Probably not worth implementing.
1637 static int screen_DECSDPT(term_screen *screen, const term_seq *seq) {
1639 * DECSDPT - select-digital-printed-data-type
1641 * Probably not worth implementing.
1647 static int screen_DECSED(term_screen *screen, const term_seq *seq) {
1649 * DECSED - selective-erase-in-display
1650 * This control function erases some or all of the erasable characters
1651 * in the display. DECSED can only erase characters defined as erasable
1652 * by the DECSCA control function. DECSED works inside or outside the
1653 * scrolling margins.
1655 * @args[0] defines which regions are erased. If it is 0, all cells from
1656 * the cursor (inclusive) till the end of the display are erase. If it
1657 * is 1, all cells from the start of the display till the cursor
1658 * (inclusive) are erased. If it is 2, all cells are erased.
1664 unsigned int mode = 0;
1666 if (seq->args[0] > 0)
1667 mode = seq->args[0];
1671 term_page_erase(screen->page,
1672 screen->cursor_x, screen->cursor_y,
1673 screen->page->width, screen->page->height,
1674 &screen->attr, screen->age, true);
1677 term_page_erase(screen->page,
1679 screen->cursor_x, screen->cursor_y,
1680 &screen->attr, screen->age, true);
1683 term_page_erase(screen->page,
1685 screen->page->width, screen->page->height,
1686 &screen->attr, screen->age, true);
1693 static int screen_DECSEL(term_screen *screen, const term_seq *seq) {
1695 * DECSEL - selective-erase-in-line
1696 * This control function erases some or all of the erasable characters
1697 * in a single line of text. DECSEL erases only those characters defined
1698 * as erasable by the DECSCA control function. DECSEL works inside or
1699 * outside the scrolling margins.
1701 * @args[0] defines the region to be erased. If it is 0, all cells from
1702 * the cursor (inclusive) till the end of the line are erase. If it is
1703 * 1, all cells from the start of the line till the cursor (inclusive)
1704 * are erased. If it is 2, the whole line of the cursor is erased.
1710 unsigned int mode = 0;
1712 if (seq->args[0] > 0)
1713 mode = seq->args[0];
1717 term_page_erase(screen->page,
1718 screen->cursor_x, screen->cursor_y,
1719 screen->page->width, screen->cursor_y,
1720 &screen->attr, screen->age, true);
1723 term_page_erase(screen->page,
1724 0, screen->cursor_y,
1725 screen->cursor_x, screen->cursor_y,
1726 &screen->attr, screen->age, true);
1729 term_page_erase(screen->page,
1730 0, screen->cursor_y,
1731 screen->page->width, screen->cursor_y,
1732 &screen->attr, screen->age, true);
1739 static int screen_DECSERA(term_screen *screen, const term_seq *seq) {
1741 * DECSERA - selective-erase-rectangular-area
1743 * Probably not worth implementing.
1749 static int screen_DECSFC(term_screen *screen, const term_seq *seq) {
1751 * DECSFC - select-flow-control
1753 * Probably not worth implementing.
1759 static int screen_DECSKCV(term_screen *screen, const term_seq *seq) {
1761 * DECSKCV - set-key-click-volume
1763 * Probably not worth implementing.
1769 static int screen_DECSLCK(term_screen *screen, const term_seq *seq) {
1771 * DECSLCK - set-lock-key-style
1773 * Probably not worth implementing.
1779 static int screen_DECSLE(term_screen *screen, const term_seq *seq) {
1781 * DECSLE - select-locator-events
1789 static int screen_DECSLPP(term_screen *screen, const term_seq *seq) {
1791 * DECSLPP - set-lines-per-page
1792 * Set the number of lines used for the page. @args[0] specifies the
1793 * number of lines to be used. DEC only allows a limited number of
1794 * choices, however, we allow all integers. 0 is equivalent to 24.
1805 static int screen_DECSLRM_OR_SC(term_screen *screen, const term_seq *seq) {
1807 * DECSLRM_OR_SC - set-left-and-right-margins or save-cursor
1809 * TODO: Detect save-cursor and run it. DECSLRM is not worth
1816 static int screen_DECSMBV(term_screen *screen, const term_seq *seq) {
1818 * DECSMBV - set-margin-bell-volume
1820 * Probably not worth implementing.
1826 static int screen_DECSMKR(term_screen *screen, const term_seq *seq) {
1828 * DECSMKR - select-modifier-key-reporting
1830 * Probably not worth implementing.
1836 static int screen_DECSNLS(term_screen *screen, const term_seq *seq) {
1838 * DECSNLS - set-lines-per-screen
1840 * Probably not worth implementing.
1846 static int screen_DECSPP(term_screen *screen, const term_seq *seq) {
1848 * DECSPP - set-port-parameter
1850 * Probably not worth implementing.
1856 static int screen_DECSPPCS(term_screen *screen, const term_seq *seq) {
1858 * DECSPPCS - select-pro-printer-character-set
1860 * Probably not worth implementing.
1866 static int screen_DECSPRTT(term_screen *screen, const term_seq *seq) {
1868 * DECSPRTT - select-printer-type
1870 * Probably not worth implementing.
1876 static int screen_DECSR(term_screen *screen, const term_seq *seq) {
1878 * DECSR - secure-reset
1880 * Probably not worth implementing.
1886 static int screen_DECSRFR(term_screen *screen, const term_seq *seq) {
1888 * DECSRFR - select-refresh-rate
1890 * Probably not worth implementing.
1896 static int screen_DECSSCLS(term_screen *screen, const term_seq *seq) {
1898 * DECSSCLS - set-scroll-speed
1900 * Probably not worth implementing.
1906 static int screen_DECSSDT(term_screen *screen, const term_seq *seq) {
1908 * DECSSDT - select-status-display-line-type
1910 * Probably not worth implementing.
1916 static int screen_DECSSL(term_screen *screen, const term_seq *seq) {
1918 * DECSSL - select-setup-language
1920 * Probably not worth implementing.
1926 static int screen_DECST8C(term_screen *screen, const term_seq *seq) {
1928 * DECST8C - set-tab-at-every-8-columns
1929 * Clear the tab-ruler and reset it to a tab at every 8th column,
1930 * starting at 9 (though, setting a tab at 1 is fine as it has no
1936 for (i = 0; i < screen->page->width; i += 8)
1937 screen->tabs[i / 8] = 0x1;
1942 static int screen_DECSTBM(term_screen *screen, const term_seq *seq) {
1944 * DECSTBM - set-top-and-bottom-margins
1945 * This control function sets the top and bottom margins for the current
1946 * page. You cannot perform scrolling outside the margins.
1948 * @args[0] defines the top margin, @args[1] defines the bottom margin.
1949 * The bottom margin must be lower than the top-margin.
1951 * This call resets the cursor position to 0/0 of the page.
1955 * args[1]: last page-line
1958 unsigned int top, bottom;
1961 bottom = screen->page->height;
1963 if (seq->args[0] > 0)
1965 if (seq->args[1] > 0)
1966 bottom = seq->args[1];
1968 if (top > screen->page->height)
1969 top = screen->page->height;
1970 if (bottom > screen->page->height)
1971 bottom = screen->page->height;
1973 if (top >= bottom || top > screen->page->height || bottom > screen->page->height) {
1975 bottom = screen->page->height;
1978 term_page_set_scroll_region(screen->page_main, top - 1, bottom - top + 1);
1979 term_page_set_scroll_region(screen->page_alt, top - 1, bottom - top + 1);
1980 screen_cursor_clear_wrap(screen);
1981 screen_cursor_set(screen, 0, 0);
1986 static int screen_DECSTR(term_screen *screen, const term_seq *seq) {
1988 * DECSTR - soft-terminal-reset
1989 * Perform a soft reset to the default values.
1992 term_screen_soft_reset(screen);
1997 static int screen_DECSTRL(term_screen *screen, const term_seq *seq) {
1999 * DECSTRL - set-transmit-rate-limit
2001 * Probably not worth implementing.
2007 static int screen_DECSWBV(term_screen *screen, const term_seq *seq) {
2009 * DECSWBV - set-warning-bell-volume
2011 * Probably not worth implementing.
2017 static int screen_DECSWL(term_screen *screen, const term_seq *seq) {
2019 * DECSWL - single-width-single-height-line
2021 * Probably not worth implementing.
2027 static int screen_DECTID(term_screen *screen, const term_seq *seq) {
2029 * DECTID - select-terminal-id
2031 * Probably not worth implementing.
2037 static int screen_DECTME(term_screen *screen, const term_seq *seq) {
2039 * DECTME - terminal-mode-emulation
2041 * Probably not worth implementing.
2047 static int screen_DECTST(term_screen *screen, const term_seq *seq) {
2049 * DECTST - invoke-confidence-test
2051 * Probably not worth implementing.
2057 static int screen_DL(term_screen *screen, const term_seq *seq) {
2060 * This control function deletes one or more lines in the scrolling
2061 * region, starting with the line that has the cursor. @args[0] defines
2062 * the number of lines to delete. 0 is treated the same as 1.
2063 * As lines are deleted, lines below the cursor and in the scrolling
2064 * region move up. The terminal adds blank lines with no visual
2065 * character attributes at the bottom of the scrolling region. If it is
2066 * greater than the number of lines remaining on the page, DL deletes
2067 * only the remaining lines. DL has no effect outside the scrolling
2074 unsigned int num = 1;
2076 if (seq->args[0] > 0)
2079 term_page_delete_lines(screen->page, screen->cursor_y, num, &screen->attr, screen->age);
2084 static int screen_DSR_ANSI(term_screen *screen, const term_seq *seq) {
2086 * DSR_ANSI - device-status-report-ansi
2094 static int screen_DSR_DEC(term_screen *screen, const term_seq *seq) {
2096 * DSR_DEC - device-status-report-dec
2104 static int screen_ECH(term_screen *screen, const term_seq *seq) {
2106 * ECH - erase-character
2107 * This control function erases one or more characters, from the cursor
2108 * position to the right. ECH clears character attributes from erased
2109 * character positions. ECH works inside or outside the scrolling
2111 * @args[0] defines the number of characters to erase. 0 is treated the
2118 unsigned int num = 1;
2120 if (seq->args[0] > 0)
2123 term_page_erase(screen->page,
2124 screen->cursor_x, screen->cursor_y,
2125 screen->cursor_x + num, screen->cursor_y,
2126 &screen->attr, screen->age, false);
2131 static int screen_ED(term_screen *screen, const term_seq *seq) {
2133 * ED - erase-in-display
2134 * This control function erases characters from part or all of the
2135 * display. When you erase complete lines, they become single-height,
2136 * single-width lines, with all visual character attributes cleared. ED
2137 * works inside or outside the scrolling margins.
2139 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2140 * till the end of the screen. 1 means from the start of the screen till
2141 * the cursor (inclusive) and 2 means the whole screen.
2147 unsigned int mode = 0;
2149 if (seq->args[0] > 0)
2150 mode = seq->args[0];
2154 term_page_erase(screen->page,
2155 screen->cursor_x, screen->cursor_y,
2156 screen->page->width, screen->page->height,
2157 &screen->attr, screen->age, false);
2160 term_page_erase(screen->page,
2162 screen->cursor_x, screen->cursor_y,
2163 &screen->attr, screen->age, false);
2166 term_page_erase(screen->page,
2168 screen->page->width, screen->page->height,
2169 &screen->attr, screen->age, false);
2176 static int screen_EL(term_screen *screen, const term_seq *seq) {
2178 * EL - erase-in-line
2179 * This control function erases characters on the line that has the
2180 * cursor. EL clears all character attributes from erased character
2181 * positions. EL works inside or outside the scrolling margins.
2183 * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2184 * till the end of the line. 1 means from the start of the line till the
2185 * cursor (inclusive) and 2 means the whole line.
2191 unsigned int mode = 0;
2193 if (seq->args[0] > 0)
2194 mode = seq->args[0];
2198 term_page_erase(screen->page,
2199 screen->cursor_x, screen->cursor_y,
2200 screen->page->width, screen->cursor_y,
2201 &screen->attr, screen->age, false);
2204 term_page_erase(screen->page,
2205 0, screen->cursor_y,
2206 screen->cursor_x, screen->cursor_y,
2207 &screen->attr, screen->age, false);
2210 term_page_erase(screen->page,
2211 0, screen->cursor_y,
2212 screen->page->width, screen->cursor_y,
2213 &screen->attr, screen->age, false);
2220 static int screen_ENQ(term_screen *screen, const term_seq *seq) {
2223 * Transmit the answerback-string. If none is set, do nothing.
2226 if (screen->answerback)
2227 return screen_write(screen, screen->answerback, strlen(screen->answerback));
2232 static int screen_EPA(term_screen *screen, const term_seq *seq) {
2234 * EPA - end-of-guarded-area
2236 * TODO: What is this?
2242 static int screen_FF(term_screen *screen, const term_seq *seq) {
2245 * This causes the cursor to jump to the next line. It is treated the
2249 return screen_LF(screen, seq);
2252 static int screen_HPA(term_screen *screen, const term_seq *seq) {
2254 * HPA - horizontal-position-absolute
2255 * HPA causes the active position to be moved to the n-th horizontal
2256 * position of the active line. If an attempt is made to move the active
2257 * position past the last position on the line, then the active position
2258 * stops at the last position on the line.
2260 * @args[0] defines the horizontal position. 0 is treated as 1.
2266 unsigned int num = 1;
2268 if (seq->args[0] > 0)
2271 screen_cursor_clear_wrap(screen);
2272 screen_cursor_set(screen, num - 1, screen->cursor_y);
2277 static int screen_HPR(term_screen *screen, const term_seq *seq) {
2279 * HPR - horizontal-position-relative
2280 * HPR causes the active position to be moved to the n-th following
2281 * horizontal position of the active line. If an attempt is made to move
2282 * the active position past the last position on the line, then the
2283 * active position stops at the last position on the line.
2285 * @args[0] defines the horizontal position. 0 is treated as 1.
2291 unsigned int num = 1;
2293 if (seq->args[0] > 0)
2296 screen_cursor_clear_wrap(screen);
2297 screen_cursor_right(screen, num);
2302 static int screen_HT(term_screen *screen, const term_seq *seq) {
2304 * HT - horizontal-tab
2305 * Moves the cursor to the next tab stop. If there are no more tab
2306 * stops, the cursor moves to the right margin. HT does not cause text
2310 screen_cursor_clear_wrap(screen);
2311 screen_cursor_right_tab(screen, 1);
2316 static int screen_HTS(term_screen *screen, const term_seq *seq) {
2318 * HTS - horizontal-tab-set
2319 * HTS sets a horizontal tab stop at the column position indicated by
2320 * the value of the active column when the terminal receives an HTS.
2322 * Executing an HTS does not effect the other horizontal tab stop
2328 pos = screen->cursor_x;
2329 if (screen->page->width > 0)
2330 screen->tabs[pos / 8] |= 1U << (pos % 8);
2335 static int screen_HVP(term_screen *screen, const term_seq *seq) {
2337 * HVP - horizontal-and-vertical-position
2338 * This control function works the same as the cursor position (CUP)
2339 * function. Origin mode (DECOM) selects line numbering and the ability
2340 * to move the cursor into margins.
2347 return screen_CUP(screen, seq);
2350 static int screen_ICH(term_screen *screen, const term_seq *seq) {
2352 * ICH - insert-character
2353 * This control function inserts one or more space (SP) characters
2354 * starting at the cursor position. @args[0] is the number of characters
2355 * to insert. 0 is treated as 1.
2357 * The ICH sequence inserts blank characters with the normal
2358 * character attribute. The cursor remains at the beginning of the blank
2359 * characters. Text between the cursor and right margin moves to the
2360 * right. Characters scrolled past the right margin are lost. ICH has no
2361 * effect outside the scrolling margins.
2367 unsigned int num = 1;
2369 if (seq->args[0] > 0)
2372 screen_cursor_clear_wrap(screen);
2373 term_page_insert_cells(screen->page, screen->cursor_x, screen->cursor_y, num, &screen->attr, screen->age);
2378 static int screen_IL(term_screen *screen, const term_seq *seq) {
2381 * This control function inserts one or more blank lines, starting at
2382 * the cursor. @args[0] is the number of lines to insert. 0 is treated
2385 * As lines are inserted, lines below the cursor and in the scrolling
2386 * region move down. Lines scrolled off the page are lost. IL has no
2387 * effect outside the page margins.
2393 unsigned int num = 1;
2395 if (seq->args[0] > 0)
2398 screen_cursor_clear_wrap(screen);
2399 term_page_insert_lines(screen->page, screen->cursor_y, num, &screen->attr, screen->age);
2404 static int screen_IND(term_screen *screen, const term_seq *seq) {
2407 * IND moves the cursor down one line in the same column. If the cursor
2408 * is at the bottom margin, then the screen performs a scroll-up.
2411 screen_cursor_down(screen, 1, true);
2416 static int screen_LF(term_screen *screen, const term_seq *seq) {
2419 * Causes a line feed or a new line operation, depending on the setting
2420 * of line feed/new line mode.
2423 screen_cursor_down(screen, 1, true);
2424 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
2425 screen_cursor_left(screen, screen->cursor_x);
2430 static int screen_LS1R(term_screen *screen, const term_seq *seq) {
2432 * LS1R - locking-shift-1-right
2436 screen->gr = &screen->g1;
2441 static int screen_LS2(term_screen *screen, const term_seq *seq) {
2443 * LS2 - locking-shift-2
2447 screen->gl = &screen->g2;
2452 static int screen_LS2R(term_screen *screen, const term_seq *seq) {
2454 * LS2R - locking-shift-2-right
2458 screen->gr = &screen->g2;
2463 static int screen_LS3(term_screen *screen, const term_seq *seq) {
2465 * LS3 - locking-shift-3
2469 screen->gl = &screen->g3;
2474 static int screen_LS3R(term_screen *screen, const term_seq *seq) {
2476 * LS3R - locking-shift-3-right
2480 screen->gr = &screen->g3;
2485 static int screen_MC_ANSI(term_screen *screen, const term_seq *seq) {
2487 * MC_ANSI - media-copy-ansi
2489 * Probably not worth implementing.
2495 static int screen_MC_DEC(term_screen *screen, const term_seq *seq) {
2497 * MC_DEC - media-copy-dec
2499 * Probably not worth implementing.
2505 static int screen_NEL(term_screen *screen, const term_seq *seq) {
2508 * Moves cursor to first position on next line. If cursor is at bottom
2509 * margin, then screen performs a scroll-up.
2512 screen_cursor_clear_wrap(screen);
2513 screen_cursor_down(screen, 1, true);
2514 screen_cursor_set(screen, 0, screen->cursor_y);
2519 static int screen_NP(term_screen *screen, const term_seq *seq) {
2522 * This control function moves the cursor forward to the home position
2523 * on one of the following pages in page memory. If there is only one
2524 * page, then the terminal ignores NP.
2525 * If NP tries to move the cursor past the last page in memory, then the
2526 * cursor stops at the last page.
2528 * @args[0] defines the number of pages to forward. 0 is treated as 1.
2533 * Probably not worth implementing. We only support a single page.
2539 static int screen_NULL(term_screen *screen, const term_seq *seq) {
2542 * The NULL operation does nothing. ASCII NULL is always ignored.
2548 static int screen_PP(term_screen *screen, const term_seq *seq) {
2550 * PP - preceding-page
2551 * This control function moves the cursor backward to the home position
2552 * on one of the preceding pages in page memory. If there is only one
2553 * page, then the terminal ignores PP.
2554 * If PP tries to move the cursor back farther than the first page in
2555 * memory, then the cursor stops at the first page.
2557 * @args[0] defines the number of pages to go backwards. 0 is treated
2563 * Probably not worth implementing. We only support a single page.
2569 static int screen_PPA(term_screen *screen, const term_seq *seq) {
2571 * PPA - page-position-absolute
2572 * This control function can move the cursor to the corresponding row
2573 * and column on any page in page memory. You select the page by its
2574 * number. If there is only one page, then the terminal ignores PPA.
2576 * @args[0] is the number of the page to move the cursor to. If it is
2577 * greater than the number of the last page in memory, then the cursor
2578 * stops at the last page. If it is less than the number of the first
2579 * page, then the cursor stops at the first page.
2584 * Probably not worth implementing. We only support a single page.
2590 static int screen_PPB(term_screen *screen, const term_seq *seq) {
2592 * PPB - page-position-backward
2593 * This control function moves the cursor backward to the corresponding
2594 * row and column on one of the preceding pages in page memory. If there
2595 * is only one page, then the terminal ignores PPB.
2597 * @args[0] indicates the number of pages to move the cursor backward.
2598 * If it tries to move the cursor back farther than the first page in
2599 * memory, then the cursor stops at the first page. 0 is treated as 1.
2604 * Probably not worth implementing. We only support a single page.
2610 static int screen_PPR(term_screen *screen, const term_seq *seq) {
2612 * PPR - page-position-relative
2613 * This control function moves the cursor forward to the corresponding
2614 * row and column on one of the following pages in page memory. If there
2615 * is only one page, then the terminal ignores PPR.
2617 * @args[0] indicates how many pages to move the cursor forward. If it
2618 * tries to move the cursor beyond the last page in memory, then the
2619 * cursor stops at the last page. 0 is treated as 1.
2624 * Probably not worth implementing. We only support a single page.
2630 static int screen_RC(term_screen *screen, const term_seq *seq) {
2632 * RC - restore-cursor
2635 return screen_DECRC(screen, seq);
2638 static int screen_REP(term_screen *screen, const term_seq *seq) {
2641 * Repeat the preceding graphics-character the given number of times.
2642 * @args[0] specifies how often it shall be repeated. 0 is treated as 1.
2647 * Probably not worth implementing.
2653 static int screen_RI(term_screen *screen, const term_seq *seq) {
2655 * RI - reverse-index
2656 * Moves the cursor up one line in the same column. If the cursor is at
2657 * the top margin, the page scrolls down.
2660 screen_cursor_up(screen, 1, true);
2665 static int screen_RIS(term_screen *screen, const term_seq *seq) {
2667 * RIS - reset-to-initial-state
2668 * This control function causes a nonvolatile memory (NVR) recall to
2669 * occur. RIS replaces all set-up features with their saved settings.
2671 * The terminal stores these saved settings in NVR memory. The saved
2672 * setting for a feature is the same as the factory-default setting,
2673 * unless you saved a new setting.
2676 term_screen_hard_reset(screen);
2681 static int screen_RM_ANSI(term_screen *screen, const term_seq *seq) {
2683 * RM_ANSI - reset-mode-ansi
2685 * TODO: implement (see VT510rm manual)
2690 for (i = 0; i < seq->n_args; ++i)
2691 screen_mode_change(screen, seq->args[i], false, false);
2696 static int screen_RM_DEC(term_screen *screen, const term_seq *seq) {
2698 * RM_DEC - reset-mode-dec
2699 * This is the same as RM_ANSI but for DEC modes.
2704 for (i = 0; i < seq->n_args; ++i)
2705 screen_mode_change(screen, seq->args[i], true, false);
2710 static int screen_S7C1T(term_screen *screen, const term_seq *seq) {
2712 * S7C1T - set-7bit-c1-terminal
2713 * This causes the terminal to start sending C1 controls as 7bit
2714 * sequences instead of 8bit C1 controls.
2715 * This is ignored if the terminal is below level-2 emulation mode
2716 * (VT100 and below), the terminal already sends 7bit controls then.
2719 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2720 screen->flags |= TERM_FLAG_7BIT_MODE;
2725 static int screen_S8C1T(term_screen *screen, const term_seq *seq) {
2727 * S8C1T - set-8bit-c1-terminal
2728 * This causes the terminal to start sending C1 controls as 8bit C1
2729 * control instead of 7bit sequences.
2730 * This is ignored if the terminal is below level-2 emulation mode
2731 * (VT100 and below). The terminal always sends 7bit controls in those
2735 if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2736 screen->flags &= ~TERM_FLAG_7BIT_MODE;
2741 static int screen_SCS(term_screen *screen, const term_seq *seq) {
2743 * SCS - select-character-set
2744 * Designate character sets to G-sets. The mapping from intermediates
2745 * and terminal characters in the escape sequence to G-sets and
2746 * character-sets is non-trivial and implemented separately. See there
2747 * for more information.
2748 * This call simply sets the selected G-set to the desired
2752 term_charset *cs = NULL;
2754 /* TODO: support more of them? */
2755 switch (seq->charset) {
2756 case TERM_CHARSET_ISO_LATIN1_SUPPLEMENTAL:
2757 case TERM_CHARSET_ISO_LATIN2_SUPPLEMENTAL:
2758 case TERM_CHARSET_ISO_LATIN5_SUPPLEMENTAL:
2759 case TERM_CHARSET_ISO_GREEK_SUPPLEMENTAL:
2760 case TERM_CHARSET_ISO_HEBREW_SUPPLEMENTAL:
2761 case TERM_CHARSET_ISO_LATIN_CYRILLIC:
2764 case TERM_CHARSET_DEC_SPECIAL_GRAPHIC:
2765 cs = &term_dec_special_graphics;
2767 case TERM_CHARSET_DEC_SUPPLEMENTAL:
2768 cs = &term_dec_supplemental_graphics;
2770 case TERM_CHARSET_DEC_TECHNICAL:
2771 case TERM_CHARSET_CYRILLIC_DEC:
2772 case TERM_CHARSET_DUTCH_NRCS:
2773 case TERM_CHARSET_FINNISH_NRCS:
2774 case TERM_CHARSET_FRENCH_NRCS:
2775 case TERM_CHARSET_FRENCH_CANADIAN_NRCS:
2776 case TERM_CHARSET_GERMAN_NRCS:
2777 case TERM_CHARSET_GREEK_DEC:
2778 case TERM_CHARSET_GREEK_NRCS:
2779 case TERM_CHARSET_HEBREW_DEC:
2780 case TERM_CHARSET_HEBREW_NRCS:
2781 case TERM_CHARSET_ITALIAN_NRCS:
2782 case TERM_CHARSET_NORWEGIAN_DANISH_NRCS:
2783 case TERM_CHARSET_PORTUGUESE_NRCS:
2784 case TERM_CHARSET_RUSSIAN_NRCS:
2785 case TERM_CHARSET_SCS_NRCS:
2786 case TERM_CHARSET_SPANISH_NRCS:
2787 case TERM_CHARSET_SWEDISH_NRCS:
2788 case TERM_CHARSET_SWISS_NRCS:
2789 case TERM_CHARSET_TURKISH_DEC:
2790 case TERM_CHARSET_TURKISH_NRCS:
2793 case TERM_CHARSET_USERPREF_SUPPLEMENTAL:
2797 if (seq->intermediates & TERM_SEQ_FLAG_POPEN)
2798 screen->g0 = cs ? : &term_unicode_lower;
2799 else if (seq->intermediates & TERM_SEQ_FLAG_PCLOSE)
2800 screen->g1 = cs ? : &term_unicode_upper;
2801 else if (seq->intermediates & TERM_SEQ_FLAG_MULT)
2802 screen->g2 = cs ? : &term_unicode_lower;
2803 else if (seq->intermediates & TERM_SEQ_FLAG_PLUS)
2804 screen->g3 = cs ? : &term_unicode_upper;
2805 else if (seq->intermediates & TERM_SEQ_FLAG_MINUS)
2806 screen->g1 = cs ? : &term_unicode_upper;
2807 else if (seq->intermediates & TERM_SEQ_FLAG_DOT)
2808 screen->g2 = cs ? : &term_unicode_lower;
2809 else if (seq->intermediates & TERM_SEQ_FLAG_SLASH)
2810 screen->g3 = cs ? : &term_unicode_upper;
2815 static int screen_SD(term_screen *screen, const term_seq *seq) {
2818 * This control function moves the user window down a specified number
2819 * of lines in page memory.
2820 * @args[0] is the number of lines to move the
2821 * user window up in page memory. New lines appear at the top of the
2822 * display. Old lines disappear at the bottom of the display. You
2823 * cannot pan past the top margin of the current page. 0 is treated
2830 unsigned int num = 1;
2832 if (seq->args[0] > 0)
2835 term_page_scroll_down(screen->page, num, &screen->attr, screen->age, NULL);
2840 static int screen_SGR(term_screen *screen, const term_seq *seq) {
2842 * SGR - select-graphics-rendition
2846 unsigned int i, code;
2849 if (seq->n_args < 1) {
2854 for (i = 0; i < seq->n_args; ++i) {
2858 screen->attr.bold = 1;
2861 screen->attr.italic = 1;
2864 screen->attr.underline = 1;
2867 screen->attr.blink = 1;
2870 screen->attr.inverse = 1;
2873 screen->attr.hidden = 1;
2876 screen->attr.bold = 0;
2879 screen->attr.italic = 0;
2882 screen->attr.underline = 0;
2885 screen->attr.blink = 0;
2888 screen->attr.inverse = 0;
2891 screen->attr.hidden = 0;
2894 screen->attr.fg.ccode = v - 30 + TERM_CCODE_BLACK;
2897 screen->attr.fg.ccode = 0;
2900 screen->attr.bg.ccode = v - 40 + TERM_CCODE_BLACK;
2903 screen->attr.bg.ccode = 0;
2906 screen->attr.fg.ccode = v - 90 + TERM_CCODE_LIGHT_BLACK;
2909 screen->attr.bg.ccode = v - 100 + TERM_CCODE_LIGHT_BLACK;
2916 dst = &screen->attr.fg;
2918 dst = &screen->attr.bg;
2921 if (i >= seq->n_args)
2924 switch (seq->args[i]) {
2926 /* 24bit-color support */
2929 if (i >= seq->n_args)
2932 dst->ccode = TERM_CCODE_RGB;
2933 dst->red = (seq->args[i - 2] >= 0) ? seq->args[i - 2] : 0;
2934 dst->green = (seq->args[i - 1] >= 0) ? seq->args[i - 1] : 0;
2935 dst->blue = (seq->args[i] >= 0) ? seq->args[i] : 0;
2939 /* 256-color support */
2942 if (i >= seq->n_args || seq->args[i] < 0)
2945 code = seq->args[i];
2948 } else if (code < 232) {
2949 static const uint8_t bval[] = {
2954 dst->ccode = TERM_CCODE_256;
2957 dst->blue = bval[code % 6];
2959 dst->green = bval[code % 6];
2961 dst->red = bval[code % 6];
2962 } else if (code < 256) {
2963 dst->ccode = TERM_CCODE_256;
2965 code = (code - 232) * 10 + 8;
2986 static int screen_SI(term_screen *screen, const term_seq *seq) {
2992 screen->gl = &screen->g0;
2997 static int screen_SM_ANSI(term_screen *screen, const term_seq *seq) {
2999 * SM_ANSI - set-mode-ansi
3006 for (i = 0; i < seq->n_args; ++i)
3007 screen_mode_change(screen, seq->args[i], false, true);
3012 static int screen_SM_DEC(term_screen *screen, const term_seq *seq) {
3014 * SM_DEC - set-mode-dec
3015 * This is the same as SM_ANSI but for DEC modes.
3020 for (i = 0; i < seq->n_args; ++i)
3021 screen_mode_change(screen, seq->args[i], true, true);
3026 static int screen_SO(term_screen *screen, const term_seq *seq) {
3032 screen->gl = &screen->g1;
3037 static int screen_SPA(term_screen *screen, const term_seq *seq) {
3039 * SPA - start-of-protected-area
3041 * TODO: What is this?
3047 static int screen_SS2(term_screen *screen, const term_seq *seq) {
3049 * SS2 - single-shift-2
3050 * Temporarily map G2 into GL for the next graphics character.
3053 screen->glt = &screen->g2;
3058 static int screen_SS3(term_screen *screen, const term_seq *seq) {
3060 * SS3 - single-shift-3
3061 * Temporarily map G3 into GL for the next graphics character
3064 screen->glt = &screen->g3;
3069 static int screen_ST(term_screen *screen, const term_seq *seq) {
3071 * ST - string-terminator
3072 * The string-terminator is usually part of control-sequences and
3073 * handled by the parser. In all other situations it is silently
3080 static int screen_SU(term_screen *screen, const term_seq *seq) {
3083 * This control function moves the user window up a specified number of
3084 * lines in page memory.
3085 * @args[0] is the number of lines to move the
3086 * user window down in page memory. New lines appear at the bottom of
3087 * the display. Old lines disappear at the top of the display. You
3088 * cannot pan past the bottom margin of the current page. 0 is treated
3095 unsigned int num = 1;
3097 if (seq->args[0] > 0)
3100 term_page_scroll_up(screen->page, num, &screen->attr, screen->age, screen->history);
3105 static int screen_SUB(term_screen *screen, const term_seq *seq) {
3108 * Cancel the current control-sequence and print a replacement
3109 * character. Our parser already handles this so all we have to do is
3110 * print the replacement character.
3113 static const term_seq rep = {
3114 .type = TERM_SEQ_GRAPHIC,
3115 .command = TERM_CMD_GRAPHIC,
3116 .terminator = 0xfffd,
3119 return screen_GRAPHIC(screen, &rep);
3122 static int screen_TBC(term_screen *screen, const term_seq *seq) {
3125 * This clears tab-stops. If @args[0] is 0, the tab-stop at the current
3126 * cursor position is cleared. If it is 3, all tab stops are cleared.
3132 unsigned int mode = 0, pos;
3134 if (seq->args[0] > 0)
3135 mode = seq->args[0];
3139 pos = screen->cursor_x;
3140 if (screen->page->width > 0)
3141 screen->tabs[pos / 8] &= ~(1U << (pos % 8));
3144 if (screen->page->width > 0)
3145 memset(screen->tabs, 0, (screen->page->width + 7) / 8);
3152 static int screen_VPA(term_screen *screen, const term_seq *seq) {
3154 * VPA - vertical-line-position-absolute
3155 * VPA causes the active position to be moved to the corresponding
3156 * horizontal position. @args[0] specifies the line to jump to. If an
3157 * attempt is made to move the active position below the last line, then
3158 * the active position stops on the last line. 0 is treated as 1.
3164 unsigned int pos = 1;
3166 if (seq->args[0] > 0)
3169 screen_cursor_clear_wrap(screen);
3170 screen_cursor_set_rel(screen, screen->cursor_x, pos - 1);
3175 static int screen_VPR(term_screen *screen, const term_seq *seq) {
3177 * VPR - vertical-line-position-relative
3178 * VPR causes the active position to be moved to the corresponding
3179 * horizontal position. @args[0] specifies the number of lines to jump
3180 * down relative to the current cursor position. If an attempt is made
3181 * to move the active position below the last line, the active position
3182 * stops at the last line. 0 is treated as 1.
3188 unsigned int num = 1;
3190 if (seq->args[0] > 0)
3193 screen_cursor_clear_wrap(screen);
3194 screen_cursor_down(screen, num, false);
3199 static int screen_VT(term_screen *screen, const term_seq *seq) {
3202 * This causes a vertical jump by one line. Terminals treat it exactly
3206 return screen_LF(screen, seq);
3209 static int screen_XTERM_CLLHP(term_screen *screen, const term_seq *seq) {
3211 * XTERM_CLLHP - xterm-cursor-lower-left-hp-bugfix
3212 * Move the cursor to the lower-left corner of the page. This is an HP
3215 * Probably not worth implementing.
3221 static int screen_XTERM_IHMT(term_screen *screen, const term_seq *seq) {
3223 * XTERM_IHMT - xterm-initiate-highlight-mouse-tracking
3225 * Probably not worth implementing.
3231 static int screen_XTERM_MLHP(term_screen *screen, const term_seq *seq) {
3233 * XTERM_MLHP - xterm-memory-lock-hp-bugfix
3235 * Probably not worth implementing.
3241 static int screen_XTERM_MUHP(term_screen *screen, const term_seq *seq) {
3243 * XTERM_MUHP - xterm-memory-unlock-hp-bugfix
3245 * Probably not worth implementing.
3251 static int screen_XTERM_RPM(term_screen *screen, const term_seq *seq) {
3253 * XTERM_RPM - xterm-restore-private-mode
3255 * Probably not worth implementing.
3261 static int screen_XTERM_RRV(term_screen *screen, const term_seq *seq) {
3263 * XTERM_RRV - xterm-reset-resource-value
3265 * Probably not worth implementing.
3271 static int screen_XTERM_RTM(term_screen *screen, const term_seq *seq) {
3273 * XTERM_RTM - xterm-reset-title-mode
3275 * Probably not worth implementing.
3281 static int screen_XTERM_SACL1(term_screen *screen, const term_seq *seq) {
3283 * XTERM_SACL1 - xterm-set-ansi-conformance-level-1
3285 * Probably not worth implementing.
3291 static int screen_XTERM_SACL2(term_screen *screen, const term_seq *seq) {
3293 * XTERM_SACL2 - xterm-set-ansi-conformance-level-2
3295 * Probably not worth implementing.
3301 static int screen_XTERM_SACL3(term_screen *screen, const term_seq *seq) {
3303 * XTERM_SACL3 - xterm-set-ansi-conformance-level-3
3305 * Probably not worth implementing.
3311 static int screen_XTERM_SDCS(term_screen *screen, const term_seq *seq) {
3313 * XTERM_SDCS - xterm-set-default-character-set
3314 * Select the default character set. We treat this the same as UTF-8 as
3315 * this is our default character set. As we always use UTF-8, this
3322 static int screen_XTERM_SGFX(term_screen *screen, const term_seq *seq) {
3324 * XTERM_SGFX - xterm-sixel-graphics
3326 * Probably not worth implementing.
3332 static int screen_XTERM_SPM(term_screen *screen, const term_seq *seq) {
3334 * XTERM_SPM - xterm-set-private-mode
3336 * Probably not worth implementing.
3342 static int screen_XTERM_SRV(term_screen *screen, const term_seq *seq) {
3344 * XTERM_SRV - xterm-set-resource-value
3346 * Probably not worth implementing.
3352 static int screen_XTERM_STM(term_screen *screen, const term_seq *seq) {
3354 * XTERM_STM - xterm-set-title-mode
3356 * Probably not worth implementing.
3362 static int screen_XTERM_SUCS(term_screen *screen, const term_seq *seq) {
3364 * XTERM_SUCS - xterm-select-utf8-character-set
3365 * Select UTF-8 as character set. This is our default on only character
3366 * set. Hence, this is a no-op.
3372 static int screen_XTERM_WM(term_screen *screen, const term_seq *seq) {
3374 * XTERM_WM - xterm-window-management
3376 * Probably not worth implementing.
3384 * The screen_feed_*() handlers take data from the user and feed it into the
3385 * screen. Once the parser has detected a sequence, we parse the command-type
3386 * and forward it to the command-dispatchers.
3389 static int screen_feed_cmd(term_screen *screen, const term_seq *seq) {
3390 switch (seq->command) {
3391 case TERM_CMD_GRAPHIC:
3392 return screen_GRAPHIC(screen, seq);
3394 return screen_BEL(screen, seq);
3396 return screen_BS(screen, seq);
3398 return screen_CBT(screen, seq);
3400 return screen_CHA(screen, seq);
3402 return screen_CHT(screen, seq);
3404 return screen_CNL(screen, seq);
3406 return screen_CPL(screen, seq);
3408 return screen_CR(screen, seq);
3410 return screen_CUB(screen, seq);
3412 return screen_CUD(screen, seq);
3414 return screen_CUF(screen, seq);
3416 return screen_CUP(screen, seq);
3418 return screen_CUU(screen, seq);
3420 return screen_DA1(screen, seq);
3422 return screen_DA2(screen, seq);
3424 return screen_DA3(screen, seq);
3426 return screen_DC1(screen, seq);
3428 return screen_DC3(screen, seq);
3430 return screen_DCH(screen, seq);
3431 case TERM_CMD_DECALN:
3432 return screen_DECALN(screen, seq);
3433 case TERM_CMD_DECANM:
3434 return screen_DECANM(screen, seq);
3435 case TERM_CMD_DECBI:
3436 return screen_DECBI(screen, seq);
3437 case TERM_CMD_DECCARA:
3438 return screen_DECCARA(screen, seq);
3439 case TERM_CMD_DECCRA:
3440 return screen_DECCRA(screen, seq);
3441 case TERM_CMD_DECDC:
3442 return screen_DECDC(screen, seq);
3443 case TERM_CMD_DECDHL_BH:
3444 return screen_DECDHL_BH(screen, seq);
3445 case TERM_CMD_DECDHL_TH:
3446 return screen_DECDHL_TH(screen, seq);
3447 case TERM_CMD_DECDWL:
3448 return screen_DECDWL(screen, seq);
3449 case TERM_CMD_DECEFR:
3450 return screen_DECEFR(screen, seq);
3451 case TERM_CMD_DECELF:
3452 return screen_DECELF(screen, seq);
3453 case TERM_CMD_DECELR:
3454 return screen_DECELR(screen, seq);
3455 case TERM_CMD_DECERA:
3456 return screen_DECERA(screen, seq);
3457 case TERM_CMD_DECFI:
3458 return screen_DECFI(screen, seq);
3459 case TERM_CMD_DECFRA:
3460 return screen_DECFRA(screen, seq);
3461 case TERM_CMD_DECIC:
3462 return screen_DECIC(screen, seq);
3463 case TERM_CMD_DECID:
3464 return screen_DECID(screen, seq);
3465 case TERM_CMD_DECINVM:
3466 return screen_DECINVM(screen, seq);
3467 case TERM_CMD_DECKBD:
3468 return screen_DECKBD(screen, seq);
3469 case TERM_CMD_DECKPAM:
3470 return screen_DECKPAM(screen, seq);
3471 case TERM_CMD_DECKPNM:
3472 return screen_DECKPNM(screen, seq);
3473 case TERM_CMD_DECLFKC:
3474 return screen_DECLFKC(screen, seq);
3475 case TERM_CMD_DECLL:
3476 return screen_DECLL(screen, seq);
3477 case TERM_CMD_DECLTOD:
3478 return screen_DECLTOD(screen, seq);
3479 case TERM_CMD_DECPCTERM:
3480 return screen_DECPCTERM(screen, seq);
3481 case TERM_CMD_DECPKA:
3482 return screen_DECPKA(screen, seq);
3483 case TERM_CMD_DECPKFMR:
3484 return screen_DECPKFMR(screen, seq);
3485 case TERM_CMD_DECRARA:
3486 return screen_DECRARA(screen, seq);
3487 case TERM_CMD_DECRC:
3488 return screen_DECRC(screen, seq);
3489 case TERM_CMD_DECREQTPARM:
3490 return screen_DECREQTPARM(screen, seq);
3491 case TERM_CMD_DECRPKT:
3492 return screen_DECRPKT(screen, seq);
3493 case TERM_CMD_DECRQCRA:
3494 return screen_DECRQCRA(screen, seq);
3495 case TERM_CMD_DECRQDE:
3496 return screen_DECRQDE(screen, seq);
3497 case TERM_CMD_DECRQKT:
3498 return screen_DECRQKT(screen, seq);
3499 case TERM_CMD_DECRQLP:
3500 return screen_DECRQLP(screen, seq);
3501 case TERM_CMD_DECRQM_ANSI:
3502 return screen_DECRQM_ANSI(screen, seq);
3503 case TERM_CMD_DECRQM_DEC:
3504 return screen_DECRQM_DEC(screen, seq);
3505 case TERM_CMD_DECRQPKFM:
3506 return screen_DECRQPKFM(screen, seq);
3507 case TERM_CMD_DECRQPSR:
3508 return screen_DECRQPSR(screen, seq);
3509 case TERM_CMD_DECRQTSR:
3510 return screen_DECRQTSR(screen, seq);
3511 case TERM_CMD_DECRQUPSS:
3512 return screen_DECRQUPSS(screen, seq);
3513 case TERM_CMD_DECSACE:
3514 return screen_DECSACE(screen, seq);
3515 case TERM_CMD_DECSASD:
3516 return screen_DECSASD(screen, seq);
3517 case TERM_CMD_DECSC:
3518 return screen_DECSC(screen, seq);
3519 case TERM_CMD_DECSCA:
3520 return screen_DECSCA(screen, seq);
3521 case TERM_CMD_DECSCL:
3522 return screen_DECSCL(screen, seq);
3523 case TERM_CMD_DECSCP:
3524 return screen_DECSCP(screen, seq);
3525 case TERM_CMD_DECSCPP:
3526 return screen_DECSCPP(screen, seq);
3527 case TERM_CMD_DECSCS:
3528 return screen_DECSCS(screen, seq);
3529 case TERM_CMD_DECSCUSR:
3530 return screen_DECSCUSR(screen, seq);
3531 case TERM_CMD_DECSDDT:
3532 return screen_DECSDDT(screen, seq);
3533 case TERM_CMD_DECSDPT:
3534 return screen_DECSDPT(screen, seq);
3535 case TERM_CMD_DECSED:
3536 return screen_DECSED(screen, seq);
3537 case TERM_CMD_DECSEL:
3538 return screen_DECSEL(screen, seq);
3539 case TERM_CMD_DECSERA:
3540 return screen_DECSERA(screen, seq);
3541 case TERM_CMD_DECSFC:
3542 return screen_DECSFC(screen, seq);
3543 case TERM_CMD_DECSKCV:
3544 return screen_DECSKCV(screen, seq);
3545 case TERM_CMD_DECSLCK:
3546 return screen_DECSLCK(screen, seq);
3547 case TERM_CMD_DECSLE:
3548 return screen_DECSLE(screen, seq);
3549 case TERM_CMD_DECSLPP:
3550 return screen_DECSLPP(screen, seq);
3551 case TERM_CMD_DECSLRM_OR_SC:
3552 return screen_DECSLRM_OR_SC(screen, seq);
3553 case TERM_CMD_DECSMBV:
3554 return screen_DECSMBV(screen, seq);
3555 case TERM_CMD_DECSMKR:
3556 return screen_DECSMKR(screen, seq);
3557 case TERM_CMD_DECSNLS:
3558 return screen_DECSNLS(screen, seq);
3559 case TERM_CMD_DECSPP:
3560 return screen_DECSPP(screen, seq);
3561 case TERM_CMD_DECSPPCS:
3562 return screen_DECSPPCS(screen, seq);
3563 case TERM_CMD_DECSPRTT:
3564 return screen_DECSPRTT(screen, seq);
3565 case TERM_CMD_DECSR:
3566 return screen_DECSR(screen, seq);
3567 case TERM_CMD_DECSRFR:
3568 return screen_DECSRFR(screen, seq);
3569 case TERM_CMD_DECSSCLS:
3570 return screen_DECSSCLS(screen, seq);
3571 case TERM_CMD_DECSSDT:
3572 return screen_DECSSDT(screen, seq);
3573 case TERM_CMD_DECSSL:
3574 return screen_DECSSL(screen, seq);
3575 case TERM_CMD_DECST8C:
3576 return screen_DECST8C(screen, seq);
3577 case TERM_CMD_DECSTBM:
3578 return screen_DECSTBM(screen, seq);
3579 case TERM_CMD_DECSTR:
3580 return screen_DECSTR(screen, seq);
3581 case TERM_CMD_DECSTRL:
3582 return screen_DECSTRL(screen, seq);
3583 case TERM_CMD_DECSWBV:
3584 return screen_DECSWBV(screen, seq);
3585 case TERM_CMD_DECSWL:
3586 return screen_DECSWL(screen, seq);
3587 case TERM_CMD_DECTID:
3588 return screen_DECTID(screen, seq);
3589 case TERM_CMD_DECTME:
3590 return screen_DECTME(screen, seq);
3591 case TERM_CMD_DECTST:
3592 return screen_DECTST(screen, seq);
3594 return screen_DL(screen, seq);
3595 case TERM_CMD_DSR_ANSI:
3596 return screen_DSR_ANSI(screen, seq);
3597 case TERM_CMD_DSR_DEC:
3598 return screen_DSR_DEC(screen, seq);
3600 return screen_ECH(screen, seq);
3602 return screen_ED(screen, seq);
3604 return screen_EL(screen, seq);
3606 return screen_ENQ(screen, seq);
3608 return screen_EPA(screen, seq);
3610 return screen_FF(screen, seq);
3612 return screen_HPA(screen, seq);
3614 return screen_HPR(screen, seq);
3616 return screen_HT(screen, seq);
3618 return screen_HTS(screen, seq);
3620 return screen_HVP(screen, seq);
3622 return screen_ICH(screen, seq);
3624 return screen_IL(screen, seq);
3626 return screen_IND(screen, seq);
3628 return screen_LF(screen, seq);
3630 return screen_LS1R(screen, seq);
3632 return screen_LS2(screen, seq);
3634 return screen_LS2R(screen, seq);
3636 return screen_LS3(screen, seq);
3638 return screen_LS3R(screen, seq);
3639 case TERM_CMD_MC_ANSI:
3640 return screen_MC_ANSI(screen, seq);
3641 case TERM_CMD_MC_DEC:
3642 return screen_MC_DEC(screen, seq);
3644 return screen_NEL(screen, seq);
3646 return screen_NP(screen, seq);
3648 return screen_NULL(screen, seq);
3650 return screen_PP(screen, seq);
3652 return screen_PPA(screen, seq);
3654 return screen_PPB(screen, seq);
3656 return screen_PPR(screen, seq);
3658 return screen_RC(screen, seq);
3660 return screen_REP(screen, seq);
3662 return screen_RI(screen, seq);
3664 return screen_RIS(screen, seq);
3665 case TERM_CMD_RM_ANSI:
3666 return screen_RM_ANSI(screen, seq);
3667 case TERM_CMD_RM_DEC:
3668 return screen_RM_DEC(screen, seq);
3669 case TERM_CMD_S7C1T:
3670 return screen_S7C1T(screen, seq);
3671 case TERM_CMD_S8C1T:
3672 return screen_S8C1T(screen, seq);
3674 return screen_SCS(screen, seq);
3676 return screen_SD(screen, seq);
3678 return screen_SGR(screen, seq);
3680 return screen_SI(screen, seq);
3681 case TERM_CMD_SM_ANSI:
3682 return screen_SM_ANSI(screen, seq);
3683 case TERM_CMD_SM_DEC:
3684 return screen_SM_DEC(screen, seq);
3686 return screen_SO(screen, seq);
3688 return screen_SPA(screen, seq);
3690 return screen_SS2(screen, seq);
3692 return screen_SS3(screen, seq);
3694 return screen_ST(screen, seq);
3696 return screen_SU(screen, seq);
3698 return screen_SUB(screen, seq);
3700 return screen_TBC(screen, seq);
3702 return screen_VPA(screen, seq);
3704 return screen_VPR(screen, seq);
3706 return screen_VT(screen, seq);
3707 case TERM_CMD_XTERM_CLLHP:
3708 return screen_XTERM_CLLHP(screen, seq);
3709 case TERM_CMD_XTERM_IHMT:
3710 return screen_XTERM_IHMT(screen, seq);
3711 case TERM_CMD_XTERM_MLHP:
3712 return screen_XTERM_MLHP(screen, seq);
3713 case TERM_CMD_XTERM_MUHP:
3714 return screen_XTERM_MUHP(screen, seq);
3715 case TERM_CMD_XTERM_RPM:
3716 return screen_XTERM_RPM(screen, seq);
3717 case TERM_CMD_XTERM_RRV:
3718 return screen_XTERM_RRV(screen, seq);
3719 case TERM_CMD_XTERM_RTM:
3720 return screen_XTERM_RTM(screen, seq);
3721 case TERM_CMD_XTERM_SACL1:
3722 return screen_XTERM_SACL1(screen, seq);
3723 case TERM_CMD_XTERM_SACL2:
3724 return screen_XTERM_SACL2(screen, seq);
3725 case TERM_CMD_XTERM_SACL3:
3726 return screen_XTERM_SACL3(screen, seq);
3727 case TERM_CMD_XTERM_SDCS:
3728 return screen_XTERM_SDCS(screen, seq);
3729 case TERM_CMD_XTERM_SGFX:
3730 return screen_XTERM_SGFX(screen, seq);
3731 case TERM_CMD_XTERM_SPM:
3732 return screen_XTERM_SPM(screen, seq);
3733 case TERM_CMD_XTERM_SRV:
3734 return screen_XTERM_SRV(screen, seq);
3735 case TERM_CMD_XTERM_STM:
3736 return screen_XTERM_STM(screen, seq);
3737 case TERM_CMD_XTERM_SUCS:
3738 return screen_XTERM_SUCS(screen, seq);
3739 case TERM_CMD_XTERM_WM:
3740 return screen_XTERM_WM(screen, seq);
3746 int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) {
3747 const uint32_t *ucs4_str;
3748 size_t i, j, ucs4_len;
3749 const term_seq *seq;
3752 assert_return(screen, -EINVAL);
3754 /* Feed bytes into utf8 decoder and handle parsed ucs4 chars. We always
3755 * treat data as UTF-8, but the parser makes sure to fall back to raw
3756 * 8bit mode if the stream is not valid UTF-8. This should be more than
3757 * enough to support old 7bit/8bit modes. */
3758 for (i = 0; i < size; ++i) {
3759 ucs4_str = term_utf8_decode(&screen->utf8, &ucs4_len, in[i]);
3760 for (j = 0; j < ucs4_len; ++j) {
3761 r = term_parser_feed(screen->parser, &seq, ucs4_str[j]);
3764 } else if (r != TERM_SEQ_NONE) {
3765 r = screen_feed_cmd(screen, seq);
3775 int term_screen_feed_keyboard(term_screen *screen, uint32_t keysym, uint32_t ascii, uint32_t ucs4, unsigned int mods) {
3776 assert_return(screen, -EINVAL);
3783 int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) {
3788 assert_return(screen, -EINVAL);
3790 r = term_page_reserve(screen->page_main, x, y, &screen->attr, screen->age);
3794 r = term_page_reserve(screen->page_alt, x, y, &screen->attr, screen->age);
3798 if (x > screen->n_tabs) {
3799 t = realloc(screen->tabs, (x + 7) / 8);
3807 for (i = (screen->page->width + 7) / 8 * 8; i < x; i += 8)
3808 screen->tabs[i / 8] = 0x1;
3810 term_page_resize(screen->page_main, x, y, &screen->attr, screen->age, screen->history);
3811 term_page_resize(screen->page_alt, x, y, &screen->attr, screen->age, NULL);
3813 screen->cursor_x = screen_clamp_x(screen, screen->cursor_x);
3814 screen->cursor_y = screen_clamp_x(screen, screen->cursor_y);
3815 screen_cursor_clear_wrap(screen);
3820 void term_screen_soft_reset(term_screen *screen) {
3825 screen->gl = &screen->g0;
3826 screen->gr = &screen->g1;
3829 screen->g0 = &term_unicode_lower;
3830 screen->g1 = &term_unicode_upper;
3831 screen->g2 = &term_unicode_lower;
3832 screen->g3 = &term_unicode_upper;
3834 screen->page = screen->page_main;
3835 screen->history = screen->history_main;
3836 screen->flags = TERM_FLAG_7BIT_MODE;
3837 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
3838 screen->attr = screen->default_attr;
3840 screen->saved.cursor_x = 0;
3841 screen->saved.cursor_y = 0;
3842 screen->saved.attr = screen->attr;
3843 screen->saved.gl = screen->gl;
3844 screen->saved.gr = screen->gr;
3845 screen->saved.glt = NULL;
3846 screen->saved.grt = NULL;
3849 for (i = 0; i < screen->page->width; i += 8)
3850 screen->tabs[i / 8] = 0x1;
3852 term_page_set_scroll_region(screen->page_main, 0, screen->page->height);
3853 term_page_set_scroll_region(screen->page_alt, 0, screen->page->height);
3856 void term_screen_hard_reset(term_screen *screen) {
3859 term_screen_soft_reset(screen);
3861 screen->cursor_x = 0;
3862 screen->cursor_y = 0;
3863 term_page_erase(screen->page_main, 0, 0, screen->page->width, screen->page->height, &screen->attr, screen->age, false);
3864 term_page_erase(screen->page_alt, 0, 0, screen->page->width, screen->page->height, &screen->attr, screen->age, false);
3867 int term_screen_set_answerback(term_screen *screen, const char *answerback) {
3870 assert_return(screen, -EINVAL);
3873 t = strdup(answerback);
3878 free(screen->answerback);
3879 screen->answerback = t;