chiark / gitweb /
terminal: split ANSI from DEC mode changes
[elogind.git] / src / libsystemd-terminal / term-screen.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
7
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.
12
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.
17
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/>.
20 ***/
21
22 /*
23  * Terminal Screens
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.
26  *
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
29  * scrolling.
30  * If you implement new commands, make sure to document them properly.
31  *
32  * Standards:
33  *   ECMA-48
34  *   ANSI X3.64
35  *   ISO/IEC 6429
36  * References:
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
42  *   ASCII
43  *   http://en.wikipedia.org/wiki/C0_and_C1_control_codes
44  *   https://en.wikipedia.org/wiki/ANSI_color
45  */
46
47 #include <stdbool.h>
48 #include <stdint.h>
49 #include <stdlib.h>
50 #include <xkbcommon/xkbcommon-keysyms.h>
51 #include "macro.h"
52 #include "term-internal.h"
53 #include "util.h"
54
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;
57         int r;
58
59         assert_return(out, -EINVAL);
60
61         screen = new0(term_screen, 1);
62         if (!screen)
63                 return -ENOMEM;
64
65         screen->ref = 1;
66         screen->age = 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;
80         screen->saved_alt = screen->saved;
81
82         r = term_page_new(&screen->page_main);
83         if (r < 0)
84                 return r;
85
86         r = term_page_new(&screen->page_alt);
87         if (r < 0)
88                 return r;
89
90         r = term_parser_new(&screen->parser, false);
91         if (r < 0)
92                 return r;
93
94         r = term_history_new(&screen->history_main);
95         if (r < 0)
96                 return r;
97
98         screen->page = screen->page_main;
99         screen->history = screen->history_main;
100
101         *out = screen;
102         screen = NULL;
103         return 0;
104 }
105
106 term_screen *term_screen_ref(term_screen *screen) {
107         if (!screen)
108                 return NULL;
109
110         assert_return(screen->ref > 0, NULL);
111
112         ++screen->ref;
113         return screen;
114 }
115
116 term_screen *term_screen_unref(term_screen *screen) {
117         if (!screen)
118                 return NULL;
119
120         assert_return(screen->ref > 0, NULL);
121
122         if (--screen->ref)
123                 return NULL;
124
125         free(screen->answerback);
126         free(screen->tabs);
127         term_history_free(screen->history_main);
128         term_page_free(screen->page_alt);
129         term_page_free(screen->page_main);
130         term_parser_free(screen->parser);
131         free(screen);
132
133         return NULL;
134 }
135
136 /*
137  * Write-Helpers
138  * Unfortunately, 7bit/8bit compat mode requires us to send C1 controls encoded
139  * as 7bit if asked by the application. This is really used in the wild, so we
140  * cannot fall back to "always 7bit".
141  * screen_write() is the underlying backend which forwards any writes to the
142  * users's callback. It's the users responsibility to buffer these and write
143  * them out once their call to term_screen_feed_*() returns.
144  * The SEQ_WRITE() and SEQ_WRITE_KEY() macros allow constructing C0/C1 sequences
145  * directly in the code-base without requiring any intermediate buffer during
146  * runtime.
147  */
148
149 #define C0_CSI "\e["
150 #define C1_CSI "\x9b"
151
152 #define SEQ(_screen, _prefix_esc, _c0, _c1, _seq) \
153                 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
154                         ((_prefix_esc) ? ("\e" _c0 _seq) : (_c0 _seq)) : \
155                         ((_prefix_esc) ? ("\e" _c1 _seq) : (_c1 _seq)))
156
157 #define SEQ_SIZE(_screen, _prefix_esc, _c0, _c1, _seq) \
158                 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
159                         ((_prefix_esc) ? sizeof("\e" _c0 _seq) : sizeof(_c0 _seq)) : \
160                         ((_prefix_esc) ? sizeof("\e" _c1 _seq) : sizeof(_c1 _seq)))
161
162 #define SEQ_WRITE_KEY(_screen, _prefix_esc, _c0, _c1, _seq) \
163                 screen_write((_screen), \
164                              SEQ((_screen), (_prefix_esc), \
165                                  _c0, _c1, _seq), \
166                              SEQ_SIZE((_screen), (_prefix_esc), \
167                                      _c0, _c1, _seq) - 1)
168
169 #define SEQ_WRITE(_screen, _c0, _c1, _seq) \
170                 SEQ_WRITE_KEY((_screen), false, _c0, _c1, _seq)
171
172 static int screen_write(term_screen *screen, const void *buf, size_t len) {
173         if (len < 1 || !screen->write_fn)
174                 return 0;
175
176         return screen->write_fn(screen, screen->write_fn_data, buf, len);
177 }
178
179 /*
180  * Command Forwarding
181  * Some commands cannot be handled by the screen-layer directly. Those are
182  * forwarded to the command-handler of the caller. This is rarely used and can
183  * safely be set to NULL.
184  */
185
186 static int screen_forward(term_screen *screen, unsigned int cmd, const term_seq *seq) {
187         if (!screen->cmd_fn)
188                 return 0;
189
190         return screen->cmd_fn(screen, screen->cmd_fn_data, cmd, seq);
191 }
192
193 /*
194  * Screen Helpers
195  * These helpers implement common-operations like cursor-handler and more, which
196  * are used by several command dispatchers.
197  */
198
199 static unsigned int screen_clamp_x(term_screen *screen, unsigned int x) {
200         if (x >= screen->page->width)
201                 return (screen->page->width > 0) ? screen->page->width - 1 : 0;
202
203         return x;
204 }
205
206 static unsigned int screen_clamp_y(term_screen *screen, unsigned int y) {
207         if (y >= screen->page->height)
208                 return (screen->page->height > 0) ? screen->page->height - 1 : 0;
209
210         return y;
211 }
212
213 static bool screen_tab_is_set(term_screen *screen, unsigned int pos) {
214         if (pos >= screen->page->width)
215                 return false;
216
217         return screen->tabs[pos / 8] & (1 << (pos % 8));
218 }
219
220 static inline void screen_age_cursor(term_screen *screen) {
221         term_cell *cell;
222
223         cell = term_page_get_cell(screen->page, screen->state.cursor_x, screen->state.cursor_y);
224         if (cell)
225                 cell->age = screen->age;
226 }
227
228 static void screen_cursor_clear_wrap(term_screen *screen) {
229         screen->flags &= ~TERM_FLAG_PENDING_WRAP;
230 }
231
232 static void screen_cursor_set(term_screen *screen, unsigned int x, unsigned int y) {
233         x = screen_clamp_x(screen, x);
234         y = screen_clamp_y(screen, y);
235
236         if (x == screen->state.cursor_x && y == screen->state.cursor_y)
237                 return;
238
239         if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
240                 screen_age_cursor(screen);
241
242         screen->state.cursor_x = x;
243         screen->state.cursor_y = y;
244
245         if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
246                 screen_age_cursor(screen);
247 }
248
249 static void screen_cursor_set_rel(term_screen *screen, unsigned int x, unsigned int y) {
250         if (screen->state.origin_mode) {
251                 x = screen_clamp_x(screen, x);
252                 y = screen_clamp_x(screen, y) + screen->page->scroll_idx;
253
254                 if (y >= screen->page->scroll_idx + screen->page->scroll_num) {
255                         y = screen->page->scroll_idx + screen->page->scroll_num;
256                         if (screen->page->scroll_num > 0)
257                                 y -= 1;
258                 }
259         }
260
261         screen_cursor_set(screen, x, y);
262 }
263
264 static void screen_cursor_left(term_screen *screen, unsigned int num) {
265         if (num > screen->state.cursor_x)
266                 num = screen->state.cursor_x;
267
268         screen_cursor_set(screen, screen->state.cursor_x - num, screen->state.cursor_y);
269 }
270
271 static void screen_cursor_left_tab(term_screen *screen, unsigned int num) {
272         unsigned int i;
273
274         i = screen->state.cursor_x;
275         while (i > 0 && num > 0) {
276                 if (screen_tab_is_set(screen, --i))
277                         --num;
278         }
279
280         screen_cursor_set(screen, i, screen->state.cursor_y);
281 }
282
283 static void screen_cursor_right(term_screen *screen, unsigned int num) {
284         if (num > screen->page->width)
285                 num = screen->page->width;
286
287         screen_cursor_set(screen, screen->state.cursor_x + num, screen->state.cursor_y);
288 }
289
290 static void screen_cursor_right_tab(term_screen *screen, unsigned int num) {
291         unsigned int i;
292
293         i = screen->state.cursor_x;
294         while (i + 1 < screen->page->width && num > 0) {
295                 if (screen_tab_is_set(screen, ++i))
296                         --num;
297         }
298
299         screen_cursor_set(screen, i, screen->state.cursor_y);
300 }
301
302 static void screen_cursor_up(term_screen *screen, unsigned int num, bool scroll) {
303         unsigned int max;
304
305         if (screen->state.cursor_y < screen->page->scroll_idx) {
306                 if (num > screen->state.cursor_y)
307                         num = screen->state.cursor_y;
308
309                 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
310         } else {
311                 max = screen->state.cursor_y - screen->page->scroll_idx;
312                 if (num > max) {
313                         if (num < 1)
314                                 return;
315
316                         if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
317                                 screen_age_cursor(screen);
318
319                         if (scroll)
320                                 term_page_scroll_down(screen->page, num - max, &screen->state.attr, screen->age, NULL);
321
322                         screen->state.cursor_y = screen->page->scroll_idx;
323
324                         if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
325                                 screen_age_cursor(screen);
326                 } else {
327                         screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
328                 }
329         }
330 }
331
332 static void screen_cursor_down(term_screen *screen, unsigned int num, bool scroll) {
333         unsigned int max;
334
335         if (screen->state.cursor_y >= screen->page->scroll_idx + screen->page->scroll_num) {
336                 if (num > screen->page->height)
337                         num = screen->page->height;
338
339                 screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y - num);
340         } else {
341                 max = screen->page->scroll_idx + screen->page->scroll_num - 1 - screen->state.cursor_y;
342                 if (num > max) {
343                         if (num < 1)
344                                 return;
345
346                         if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
347                                 screen_age_cursor(screen);
348
349                         if (scroll)
350                                 term_page_scroll_up(screen->page, num - max, &screen->state.attr, screen->age, screen->history);
351
352                         screen->state.cursor_y = screen->page->scroll_idx + screen->page->scroll_num - 1;
353
354                         if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
355                                 screen_age_cursor(screen);
356                 } else {
357                         screen_cursor_set(screen, screen->state.cursor_x, screen->state.cursor_y + num);
358                 }
359         }
360 }
361
362 static void screen_save_state(term_screen *screen, term_state *where) {
363         *where = screen->state;
364 }
365
366 static void screen_restore_state(term_screen *screen, term_state *from) {
367         screen_cursor_set(screen, from->cursor_x, from->cursor_y);
368         screen->state = *from;
369 }
370
371 static void screen_reset_page(term_screen *screen, term_page *page) {
372         term_page_set_scroll_region(page, 0, page->height);
373         term_page_erase(page, 0, 0, page->width, page->height, &screen->state.attr, screen->age, false);
374 }
375
376 static void screen_change_alt(term_screen *screen, bool set) {
377         if (set) {
378                 screen->page = screen->page_alt;
379                 screen->history = NULL;
380         } else {
381                 screen->page = screen->page_main;
382                 screen->history = screen->history_main;
383         }
384
385         screen->page->age = screen->age;
386 }
387
388 static inline void set_reset(term_screen *screen, unsigned int flag, bool set) {
389         if (set)
390                 screen->flags |= flag;
391         else
392                 screen->flags &= ~flag;
393 }
394
395 static void screen_mode_change_ansi(term_screen *screen, unsigned mode, bool set) {
396         switch (mode) {
397         case 20:
398                 /*
399                  * LNM: line-feed/new-line mode
400                  * TODO
401                  */
402                 set_reset(screen, TERM_FLAG_NEWLINE_MODE, set);
403
404                 break;
405         }
406 }
407
408 static void screen_mode_change_dec(term_screen *screen, unsigned int mode, bool set) {
409         switch (mode) {
410         case 1:
411                 /*
412                  * DECCKM: cursor-keys
413                  * TODO
414                  */
415                 set_reset(screen, TERM_FLAG_CURSOR_KEYS, set);
416
417                 break;
418         case 6:
419                 /*
420                  * DECOM: origin-mode
421                  * TODO
422                  */
423                 screen->state.origin_mode = set;
424
425                 break;
426         case 7:
427                 /*
428                  * DECAWN: auto-wrap mode
429                  * TODO
430                  */
431                 screen->state.auto_wrap = set;
432
433                 break;
434         case 25:
435                 /*
436                  * DECTCEM: text-cursor-enable
437                  * TODO
438                  */
439                 set_reset(screen, TERM_FLAG_HIDE_CURSOR, !set);
440                 screen_age_cursor(screen);
441
442                 break;
443         case 47:
444                 /*
445                  * XTERM-ASB: alternate-screen-buffer
446                  * This enables/disables the alternate screen-buffer.
447                  * It effectively saves the current page content and
448                  * allows you to restore it when changing to the
449                  * original screen-buffer again.
450                  */
451                 screen_change_alt(screen, set);
452
453                 break;
454         case 1047:
455                 /*
456                  * XTERM-ASBPE: alternate-screen-buffer-post-erase
457                  * This is the same as XTERM-ASB but erases the
458                  * alternate screen-buffer before switching back to the
459                  * original buffer. Use it to discard any data on the
460                  * alternate screen buffer when done.
461                  */
462                 if (!set)
463                         screen_reset_page(screen, screen->page_alt);
464
465                 screen_change_alt(screen, set);
466
467                 break;
468         case 1048:
469                 /*
470                  * XTERM-ASBCS: alternate-screen-buffer-cursor-state
471                  * This has the same effect as DECSC/DECRC, but uses a
472                  * separate state buffer. It is usually used in
473                  * combination with alternate screen buffers to provide
474                  * stacked state storage.
475                  */
476                 if (set)
477                         screen_save_state(screen, &screen->saved_alt);
478                 else
479                         screen_restore_state(screen, &screen->saved_alt);
480
481                 break;
482         case 1049:
483                 /*
484                  * XTERM-ASBX: alternate-screen-buffer-extended
485                  * This combines XTERM-ASBPE and XTERM-ASBCS somewhat.
486                  * When enabling, state is saved, alternate screen
487                  * buffer is activated and cleared.
488                  * When disabled, alternate screen buffer is cleared,
489                  * then normal screen buffer is enabled and state is
490                  * restored.
491                  */
492                 if (set)
493                         screen_save_state(screen, &screen->saved_alt);
494
495                 screen_reset_page(screen, screen->page_alt);
496                 screen_change_alt(screen, set);
497
498                 if (!set)
499                         screen_restore_state(screen, &screen->saved_alt);
500
501                 break;
502         }
503 }
504
505 /* map a character according to current GL and GR maps */
506 static uint32_t screen_map(term_screen *screen, uint32_t val) {
507         uint32_t nval = -1U;
508
509         /* 32 and 127 always map to identity. 160 and 255 map to identity iff a
510          * 96 character set is loaded into GR. Values above 255 always map to
511          * identity. */
512         switch (val) {
513         case 33 ... 126:
514                 if (screen->state.glt) {
515                         nval = (**screen->state.glt)[val - 32];
516                         screen->state.glt = NULL;
517                 } else {
518                         nval = (**screen->state.gl)[val - 32];
519                 }
520                 break;
521         case 160 ... 255:
522                 if (screen->state.grt) {
523                         nval = (**screen->state.grt)[val - 160];
524                         screen->state.grt = NULL;
525                 } else {
526                         nval = (**screen->state.gr)[val - 160];
527                 }
528                 break;
529         }
530
531         return (nval == -1U) ? val : nval;
532 }
533
534 /*
535  * Command Handlers
536  * This is the unofficial documentation of all the TERM_CMD_* definitions. Each
537  * handled command has a separate function with an extensive comment on the
538  * semantics of the command.
539  * Note that many semantics are unknown and need to be verified. This is mostly
540  * about error-handling, though. Applications rarely rely on those features.
541  */
542
543 static int screen_DA1(term_screen *screen, const term_seq *seq);
544 static int screen_LF(term_screen *screen, const term_seq *seq);
545
546 static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) {
547         term_char_t ch = TERM_CHAR_NULL;
548         uint32_t c;
549
550         if (screen->state.cursor_x + 1 == screen->page->width
551             && screen->flags & TERM_FLAG_PENDING_WRAP
552             && screen->state.auto_wrap) {
553                 screen_cursor_down(screen, 1, true);
554                 screen_cursor_set(screen, 0, screen->state.cursor_y);
555         }
556
557         screen_cursor_clear_wrap(screen);
558
559         c = screen_map(screen, seq->terminator);
560         ch = term_char_merge(ch, screen_map(screen, c));
561         term_page_write(screen->page, screen->state.cursor_x, screen->state.cursor_y, ch, 1, &screen->state.attr, screen->age, false);
562
563         if (screen->state.cursor_x + 1 == screen->page->width)
564                 screen->flags |= TERM_FLAG_PENDING_WRAP;
565         else
566                 screen_cursor_right(screen, 1);
567
568         return 0;
569 }
570
571 static int screen_BEL(term_screen *screen, const term_seq *seq) {
572         /*
573          * BEL - sound bell tone
574          * This command should trigger an acoustic bell. Usually, this is
575          * forwarded directly to the pcspkr. However, bells have become quite
576          * uncommon and annoying, so we're not implementing them here. Instead,
577          * it's one of the commands we forward to the caller.
578          */
579
580         return screen_forward(screen, TERM_CMD_BEL, seq);
581 }
582
583 static int screen_BS(term_screen *screen, const term_seq *seq) {
584         /*
585          * BS - backspace
586          * Move cursor one cell to the left. If already at the left margin,
587          * nothing happens.
588          */
589
590         screen_cursor_clear_wrap(screen);
591         screen_cursor_left(screen, 1);
592         return 0;
593 }
594
595 static int screen_CBT(term_screen *screen, const term_seq *seq) {
596         /*
597          * CBT - cursor-backward-tabulation
598          * Move the cursor @args[0] tabs backwards (to the left). The
599          * current cursor cell, in case it's a tab, is not counted.
600          * Furthermore, the cursor cannot be moved beyond position 0 and
601          * it will stop there.
602          *
603          * Defaults:
604          *   args[0]: 1
605          */
606
607         unsigned int num = 1;
608
609         if (seq->args[0] > 0)
610                 num = seq->args[0];
611
612         screen_cursor_clear_wrap(screen);
613         screen_cursor_left_tab(screen, num);
614
615         return 0;
616 }
617
618 static int screen_CHA(term_screen *screen, const term_seq *seq) {
619         /*
620          * CHA - cursor-horizontal-absolute
621          * Move the cursor to position @args[0] in the current line. The
622          * cursor cannot be moved beyond the rightmost cell and will stop
623          * there.
624          *
625          * Defaults:
626          *   args[0]: 1
627          */
628
629         unsigned int pos = 1;
630
631         if (seq->args[0] > 0)
632                 pos = seq->args[0];
633
634         screen_cursor_clear_wrap(screen);
635         screen_cursor_set(screen, pos - 1, screen->state.cursor_y);
636
637         return 0;
638 }
639
640 static int screen_CHT(term_screen *screen, const term_seq *seq) {
641         /*
642          * CHT - cursor-horizontal-forward-tabulation
643          * Move the cursor @args[0] tabs forward (to the right). The
644          * current cursor cell, in case it's a tab, is not counted.
645          * Furthermore, the cursor cannot be moved beyond the rightmost cell
646          * and will stop there.
647          *
648          * Defaults:
649          *   args[0]: 1
650          */
651
652         unsigned int num = 1;
653
654         if (seq->args[0] > 0)
655                 num = seq->args[0];
656
657         screen_cursor_clear_wrap(screen);
658         screen_cursor_right_tab(screen, num);
659
660         return 0;
661 }
662
663 static int screen_CNL(term_screen *screen, const term_seq *seq) {
664         /*
665          * CNL - cursor-next-line
666          * Move the cursor @args[0] lines down.
667          *
668          * TODO: Does this stop at the bottom or cause a scroll-up?
669          *
670          * Defaults:
671          *   args[0]: 1
672          */
673
674         unsigned int num = 1;
675
676         if (seq->args[0] > 0)
677                 num = seq->args[0];
678
679         screen_cursor_clear_wrap(screen);
680         screen_cursor_down(screen, num, false);
681
682         return 0;
683 }
684
685 static int screen_CPL(term_screen *screen, const term_seq *seq) {
686         /*
687          * CPL - cursor-preceding-line
688          * Move the cursor @args[0] lines up.
689          *
690          * TODO: Does this stop at the top or cause a scroll-up?
691          *
692          * Defaults:
693          *   args[0]: 1
694          */
695
696         unsigned int num = 1;
697
698         if (seq->args[0] > 0)
699                 num = seq->args[0];
700
701         screen_cursor_clear_wrap(screen);
702         screen_cursor_up(screen, num, false);
703
704         return 0;
705 }
706
707 static int screen_CR(term_screen *screen, const term_seq *seq) {
708         /*
709          * CR - carriage-return
710          * Move the cursor to the left margin on the current line.
711          */
712
713         screen_cursor_clear_wrap(screen);
714         screen_cursor_set(screen, 0, screen->state.cursor_y);
715
716         return 0;
717 }
718
719 static int screen_CUB(term_screen *screen, const term_seq *seq) {
720         /*
721          * CUB - cursor-backward
722          * Move the cursor @args[0] positions to the left. The cursor stops
723          * at the left-most position.
724          *
725          * Defaults:
726          *   args[0]: 1
727          */
728
729         unsigned int num = 1;
730
731         if (seq->args[0] > 0)
732                 num = seq->args[0];
733
734         screen_cursor_clear_wrap(screen);
735         screen_cursor_left(screen, num);
736
737         return 0;
738 }
739
740 static int screen_CUD(term_screen *screen, const term_seq *seq) {
741         /*
742          * CUD - cursor-down
743          * Move the cursor @args[0] positions down. The cursor stops at the
744          * bottom margin. If it was already moved further, it stops at the
745          * bottom line.
746          *
747          * Defaults:
748          *   args[0]: 1
749          */
750
751         unsigned int num = 1;
752
753         if (seq->args[0] > 0)
754                 num = seq->args[0];
755
756         screen_cursor_clear_wrap(screen);
757         screen_cursor_down(screen, num, false);
758
759         return 0;
760 }
761
762 static int screen_CUF(term_screen *screen, const term_seq *seq) {
763         /*
764          * CUF -cursor-forward
765          * Move the cursor @args[0] positions to the right. The cursor stops
766          * at the right-most position.
767          *
768          * Defaults:
769          *   args[0]: 1
770          */
771
772         unsigned int num = 1;
773
774         if (seq->args[0] > 0)
775                 num = seq->args[0];
776
777         screen_cursor_clear_wrap(screen);
778         screen_cursor_right(screen, num);
779
780         return 0;
781 }
782
783 static int screen_CUP(term_screen *screen, const term_seq *seq) {
784         /*
785          * CUP - cursor-position
786          * Moves the cursor to position @args[1] x @args[0]. If either is 0, it
787          * is treated as 1. The positions are subject to the origin-mode and
788          * clamped to the addressable with/height.
789          *
790          * Defaults:
791          *   args[0]: 1
792          *   args[1]: 1
793          */
794
795         unsigned int x = 1, y = 1;
796
797         if (seq->args[0] > 0)
798                 y = seq->args[0];
799         if (seq->args[1] > 0)
800                 x = seq->args[1];
801
802         screen_cursor_clear_wrap(screen);
803         screen_cursor_set_rel(screen, x - 1, y - 1);
804
805         return 0;
806 }
807
808 static int screen_CUU(term_screen *screen, const term_seq *seq) {
809         /*
810          * CUU - cursor-up
811          * Move the cursor @args[0] positions up. The cursor stops at the
812          * top margin. If it was already moved further, it stops at the
813          * top line.
814          *
815          * Defaults:
816          *   args[0]: 1
817          *
818          */
819
820         unsigned int num = 1;
821
822         if (seq->args[0] > 0)
823                 num = seq->args[0];
824
825         screen_cursor_clear_wrap(screen);
826         screen_cursor_up(screen, num, false);
827
828         return 0;
829 }
830
831 static int screen_DA1(term_screen *screen, const term_seq *seq) {
832         /*
833          * DA1 - primary-device-attributes
834          * The primary DA asks for basic terminal features. We simply return
835          * a hard-coded list of features we implement.
836          * Note that the primary DA asks for supported features, not currently
837          * enabled features.
838          *
839          * The terminal's answer is:
840          *   ^[ ? 64 ; ARGS c
841          * The first argument, 64, is fixed and denotes a VT420, the last
842          * DEC-term that extended this number.
843          * All following arguments denote supported features. Note
844          * that at most 15 features can be sent (max CSI args). It is safe to
845          * send more, but clients might not be able to parse them. This is a
846          * client's problem and we shouldn't care. There is no other way to
847          * send those feature lists, so we have to extend them beyond 15 in
848          * those cases.
849          *
850          * Known modes:
851          *    1: 132 column mode
852          *       The 132 column mode is supported by the terminal.
853          *    2: printer port
854          *       A priner-port is supported and can be addressed via
855          *       control-codes.
856          *    3: ReGIS graphics
857          *       Support for ReGIS graphics is available. The ReGIS routines
858          *       provide the "remote graphics instruction set" and allow basic
859          *       vector-rendering.
860          *    4: sixel
861          *       Support of Sixel graphics is available. This provides access
862          *       to the sixel bitmap routines.
863          *    6: selective erase
864          *       The terminal supports DECSCA and related selective-erase
865          *       functions. This allows to protect specific cells from being
866          *       erased, if specified.
867          *    7: soft character set (DRCS)
868          *       TODO: ?
869          *    8: user-defined keys (UDKs)
870          *       TODO: ?
871          *    9: national-replacement character sets (NRCS)
872          *       National-replacement character-sets are available.
873          *   12: Yugoslavian (SCS)
874          *       TODO: ?
875          *   15: technical character set
876          *       The DEC technical-character-set is available.
877          *   18: windowing capability
878          *       TODO: ?
879          *   21: horizontal scrolling
880          *       TODO: ?
881          *   22: ANSII color
882          *       TODO: ?
883          *   23: Greek
884          *       TODO: ?
885          *   24: Turkish
886          *       TODO: ?
887          *   29: ANSI text locator
888          *       TODO: ?
889          *   42: ISO Latin-2 character set
890          *       TODO: ?
891          *   44: PCTerm
892          *       TODO: ?
893          *   45: soft keymap
894          *       TODO: ?
895          *   46: ASCII emulation
896          *       TODO: ?
897          */
898
899         return SEQ_WRITE(screen, C0_CSI, C1_CSI, "?64;1;6;9;15c");
900 }
901
902 static int screen_DA2(term_screen *screen, const term_seq *seq) {
903         /*
904          * DA2 - secondary-device-attributes
905          * The secondary DA asks for the terminal-ID, firmware versions and
906          * other non-primary attributes. All these values are
907          * informational-only and should not be used by the host to detect
908          * terminal features.
909          *
910          * The terminal's response is:
911          *   ^[ > 61 ; FIRMWARE ; KEYBOARD c
912          * whereas 65 is fixed for VT525 terminals, the last terminal-line that
913          * increased this number. FIRMWARE is the firmware
914          * version encoded as major/minor (20 == 2.0) and KEYBOARD is 0 for STD
915          * keyboard and 1 for PC keyboards.
916          *
917          * We replace the firmware-version with the systemd-version so clients
918          * can decode it again.
919          */
920
921         return SEQ_WRITE(screen, C0_CSI, C1_CSI, ">65;" PACKAGE_VERSION ";1c");
922 }
923
924 static int screen_DA3(term_screen *screen, const term_seq *seq) {
925         /*
926          * DA3 - tertiary-device-attributes
927          * The tertiary DA is used to query the terminal-ID.
928          *
929          * The terminal's response is:
930          *   ^P ! | XX AA BB CC ^\
931          * whereas all four parameters are hexadecimal-encoded pairs. XX
932          * denotes the manufacturing site, AA BB CC is the terminal's ID.
933          */
934
935         /* we do not support tertiary DAs */
936         return 0;
937 }
938
939 static int screen_DC1(term_screen *screen, const term_seq *seq) {
940         /*
941          * DC1 - device-control-1 or XON
942          * This clears any previous XOFF and resumes terminal-transmission.
943          */
944
945         /* we do not support XON */
946         return 0;
947 }
948
949 static int screen_DC3(term_screen *screen, const term_seq *seq) {
950         /*
951          * DC3 - device-control-3 or XOFF
952          * Stops terminal transmission. No further characters are sent until
953          * an XON is received.
954          */
955
956         /* we do not support XOFF */
957         return 0;
958 }
959
960 static int screen_DCH(term_screen *screen, const term_seq *seq) {
961         /*
962          * DCH - delete-character
963          * This deletes @argv[0] characters at the current cursor position. As
964          * characters are deleted, the remaining characters between the cursor
965          * and right margin move to the left. Character attributes move with the
966          * characters. The terminal adds blank spaces with no visual character
967          * attributes at the right margin. DCH has no effect outside the
968          * scrolling margins.
969          *
970          * Defaults:
971          *   args[0]: 1
972          */
973
974         unsigned int num = 1;
975
976         if (seq->args[0] > 0)
977                 num = seq->args[0];
978
979         screen_cursor_clear_wrap(screen);
980         term_page_delete_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age);
981
982         return 0;
983 }
984
985 static int screen_DECALN(term_screen *screen, const term_seq *seq) {
986         /*
987          * DECALN - screen-alignment-pattern
988          *
989          * Probably not worth implementing.
990          */
991
992         return 0;
993 }
994
995 static int screen_DECANM(term_screen *screen, const term_seq *seq) {
996         /*
997          * DECANM - ansi-mode
998          * Set the terminal into VT52 compatibility mode. Control sequences
999          * overlap with regular sequences so we have to detect them early before
1000          * dispatching them.
1001          *
1002          * Probably not worth implementing.
1003          */
1004
1005         return 0;
1006 }
1007
1008 static int screen_DECBI(term_screen *screen, const term_seq *seq) {
1009         /*
1010          * DECBI - back-index
1011          * This control function moves the cursor backward one column. If the
1012          * cursor is at the left margin, then all screen data within the margin
1013          * moves one column to the right. The column that shifted past the right
1014          * margin is lost.
1015          * DECBI adds a new column at the left margin with no visual attributes.
1016          * DECBI does not affect the margins. If the cursor is beyond the
1017          * left-margin at the left border, then the terminal ignores DECBI.
1018          *
1019          * Probably not worth implementing.
1020          */
1021
1022         return 0;
1023 }
1024
1025 static int screen_DECCARA(term_screen *screen, const term_seq *seq) {
1026         /*
1027          * DECCARA - change-attributes-in-rectangular-area
1028          *
1029          * Probably not worth implementing.
1030          */
1031
1032         return 0;
1033 }
1034
1035 static int screen_DECCRA(term_screen *screen, const term_seq *seq) {
1036         /*
1037          * DECCRA - copy-rectangular-area
1038          *
1039          * Probably not worth implementing.
1040          */
1041
1042         return 0;
1043 }
1044
1045 static int screen_DECDC(term_screen *screen, const term_seq *seq) {
1046         /*
1047          * DECDC - delete-column
1048          *
1049          * Probably not worth implementing.
1050          */
1051
1052         return 0;
1053 }
1054
1055 static int screen_DECDHL_BH(term_screen *screen, const term_seq *seq) {
1056         /*
1057          * DECDHL_BH - double-width-double-height-line: bottom half
1058          *
1059          * Probably not worth implementing.
1060          */
1061
1062         return 0;
1063 }
1064
1065 static int screen_DECDHL_TH(term_screen *screen, const term_seq *seq) {
1066         /*
1067          * DECDHL_TH - double-width-double-height-line: top half
1068          *
1069          * Probably not worth implementing.
1070          */
1071
1072         return 0;
1073 }
1074
1075 static int screen_DECDWL(term_screen *screen, const term_seq *seq) {
1076         /*
1077          * DECDWL - double-width-single-height-line
1078          *
1079          * Probably not worth implementing.
1080          */
1081
1082         return 0;
1083 }
1084
1085 static int screen_DECEFR(term_screen *screen, const term_seq *seq) {
1086         /*
1087          * DECEFR - enable-filter-rectangle
1088          * Defines the coordinates of a filter rectangle (top, left, bottom,
1089          * right as @args[0] to @args[3]) and activates it.
1090          * Anytime the locator is detected outside of the filter rectangle, an
1091          * outside rectangle event is generated and the rectangle is disabled.
1092          * Filter rectangles are always treated as "one-shot" events. Any
1093          * parameters that are omitted default to the current locator position.
1094          * If all parameters are omitted, any locator motion will be reported.
1095          * DECELR always cancels any prevous rectangle definition.
1096          *
1097          * The locator is usually associated with the mouse-cursor, but based
1098          * on cells instead of pixels. See DECELR how to initialize and enable
1099          * it. DECELR can also enable pixel-mode instead of cell-mode.
1100          *
1101          * TODO: implement
1102          */
1103
1104         return 0;
1105 }
1106
1107 static int screen_DECELF(term_screen *screen, const term_seq *seq) {
1108         /*
1109          * DECELF - enable-local-functions
1110          *
1111          * Probably not worth implementing.
1112          */
1113
1114         return 0;
1115 }
1116
1117 static int screen_DECELR(term_screen *screen, const term_seq *seq) {
1118         /*
1119          * DECELR - enable-locator-reporting
1120          * This changes the locator-reporting mode. @args[0] specifies the mode
1121          * to set, 0 disables locator-reporting, 1 enables it continuously, 2
1122          * enables it for a single report. @args[1] specifies the
1123          * precision-mode. 0 and 2 set the reporting to cell-precision, 1 sets
1124          * pixel-precision.
1125          *
1126          * Defaults:
1127          *   args[0]: 0
1128          *   args[1]: 0
1129          *
1130          * TODO: implement
1131          */
1132
1133         return 0;
1134 }
1135
1136 static int screen_DECERA(term_screen *screen, const term_seq *seq) {
1137         /*
1138          * DECERA - erase-rectangular-area
1139          *
1140          * Probably not worth implementing.
1141          */
1142
1143         return 0;
1144 }
1145
1146 static int screen_DECFI(term_screen *screen, const term_seq *seq) {
1147         /*
1148          * DECFI - forward-index
1149          * This control function moves the cursor forward one column. If the
1150          * cursor is at the right margin, then all screen data within the
1151          * margins moves one column to the left. The column shifted past the
1152          * left margin is lost.
1153          * DECFI adds a new column at the right margin, with no visual
1154          * attributes. DECFI does not affect margins. If the cursor is beyond
1155          * the right margin at the border of the page when the terminal
1156          * receives DECFI, then the terminal ignores DECFI.
1157          *
1158          * Probably not worth implementing.
1159          */
1160
1161         return 0;
1162 }
1163
1164 static int screen_DECFRA(term_screen *screen, const term_seq *seq) {
1165         /*
1166          * DECFRA - fill-rectangular-area
1167          *
1168          * Probably not worth implementing.
1169          */
1170
1171         return 0;
1172 }
1173
1174 static int screen_DECIC(term_screen *screen, const term_seq *seq) {
1175         /*
1176          * DECIC - insert-column
1177          *
1178          * Probably not worth implementing.
1179          */
1180
1181         return 0;
1182 }
1183
1184 static int screen_DECID(term_screen *screen, const term_seq *seq) {
1185         /*
1186          * DECID - return-terminal-id
1187          * This is an obsolete form of TERM_CMD_DA1.
1188          */
1189
1190         return screen_DA1(screen, seq);
1191 }
1192
1193 static int screen_DECINVM(term_screen *screen, const term_seq *seq) {
1194         /*
1195          * DECINVM - invoke-macro
1196          *
1197          * Probably not worth implementing.
1198          */
1199
1200         return 0;
1201 }
1202
1203 static int screen_DECKBD(term_screen *screen, const term_seq *seq) {
1204         /*
1205          * DECKBD - keyboard-language-selection
1206          *
1207          * Probably not worth implementing.
1208          */
1209
1210         return 0;
1211 }
1212
1213 static int screen_DECKPAM(term_screen *screen, const term_seq *seq) {
1214         /*
1215          * DECKPAM - keypad-application-mode
1216          * Enables the keypad-application mode. If enabled, the keypad sends
1217          * special characters instead of the printed characters. This way,
1218          * applications can detect whether a numeric key was pressed on the
1219          * top-row or on the keypad.
1220          * Default is keypad-numeric-mode.
1221          */
1222
1223         screen->flags |= TERM_FLAG_KEYPAD_MODE;
1224
1225         return 0;
1226 }
1227
1228 static int screen_DECKPNM(term_screen *screen, const term_seq *seq) {
1229         /*
1230          * DECKPNM - keypad-numeric-mode
1231          * This disables the keypad-application-mode (DECKPAM) and returns to
1232          * the keypad-numeric-mode. Keypresses on the keypad generate the same
1233          * sequences as corresponding keypresses on the main keyboard.
1234          * Default is keypad-numeric-mode.
1235          */
1236
1237         screen->flags &= ~TERM_FLAG_KEYPAD_MODE;
1238
1239         return 0;
1240 }
1241
1242 static int screen_DECLFKC(term_screen *screen, const term_seq *seq) {
1243         /*
1244          * DECLFKC - local-function-key-control
1245          *
1246          * Probably not worth implementing.
1247          */
1248
1249         return 0;
1250 }
1251
1252 static int screen_DECLL(term_screen *screen, const term_seq *seq) {
1253         /*
1254          * DECLL - load-leds
1255          *
1256          * Probably not worth implementing.
1257          */
1258
1259         return 0;
1260 }
1261
1262 static int screen_DECLTOD(term_screen *screen, const term_seq *seq) {
1263         /*
1264          * DECLTOD - load-time-of-day
1265          *
1266          * Probably not worth implementing.
1267          */
1268
1269         return 0;
1270 }
1271
1272 static int screen_DECPCTERM(term_screen *screen, const term_seq *seq) {
1273         /*
1274          * DECPCTERM - pcterm-mode
1275          * This enters/exits the PCTerm mode. Default mode is VT-mode. It can
1276          * also select parameters for scancode/keycode mappings in SCO mode.
1277          *
1278          * Definitely not worth implementing. Lets kill PCTerm/SCO modes!
1279          */
1280
1281         return 0;
1282 }
1283
1284 static int screen_DECPKA(term_screen *screen, const term_seq *seq) {
1285         /*
1286          * DECPKA - program-key-action
1287          *
1288          * Probably not worth implementing.
1289          */
1290
1291         return 0;
1292 }
1293
1294 static int screen_DECPKFMR(term_screen *screen, const term_seq *seq) {
1295         /*
1296          * DECPKFMR - program-key-free-memory-report
1297          *
1298          * Probably not worth implementing.
1299          */
1300
1301         return 0;
1302 }
1303
1304 static int screen_DECRARA(term_screen *screen, const term_seq *seq) {
1305         /*
1306          * DECRARA - reverse-attributes-in-rectangular-area
1307          *
1308          * Probably not worth implementing.
1309          */
1310
1311         return 0;
1312 }
1313
1314 static int screen_DECRC(term_screen *screen, const term_seq *seq) {
1315         /*
1316          * DECRC - restore-cursor
1317          * Restores the terminal to the state saved by the save cursor (DECSC)
1318          * function. This includes more than just the cursor-position.
1319          *
1320          * If nothing was saved by DECSC, then DECRC performs the following
1321          * actions:
1322          *   * Moves the cursor to the home position (upper left of screen).
1323          *   * Resets origin mode (DECOM).
1324          *   * Turns all character attributes off (normal setting).
1325          *   * Maps the ASCII character set into GL, and the DEC Supplemental
1326          *     Graphic set into GR.
1327          *
1328          * The terminal maintains a separate DECSC buffer for the main display
1329          * and the status line. This feature lets you save a separate operating
1330          * state for the main display and the status line.
1331          */
1332
1333         screen_restore_state(screen, &screen->saved);
1334
1335         return 0;
1336 }
1337
1338 static int screen_DECREQTPARM(term_screen *screen, const term_seq *seq) {
1339         /*
1340          * DECREQTPARM - request-terminal-parameters
1341          * The sequence DECREPTPARM is sent by the terminal controller to notify
1342          * the host of the status of selected terminal parameters. The status
1343          * sequence may be sent when requested by the host or at the terminal's
1344          * discretion. DECREPTPARM is sent upon receipt of a DECREQTPARM.
1345          *
1346          * If @args[0] is 0, this marks a request and the terminal is allowed
1347          * to send DECREPTPARM messages without request. If it is 1, the same
1348          * applies but the terminal should no longer send DECREPTPARM
1349          * unrequested.
1350          * 2 and 3 mark a report, but 3 is only used if the terminal answers as
1351          * an explicit request with @args[0] == 1.
1352          *
1353          * The other arguments are ignored in requests, but have the following
1354          * meaning in responses:
1355          *   args[1]: 1=no-parity-set 4=parity-set-and-odd 5=parity-set-and-even
1356          *   args[2]: 1=8bits-per-char 2=7bits-per-char
1357          *   args[3]: transmission-speed
1358          *   args[4]: receive-speed
1359          *   args[5]: 1=bit-rate-multiplier-is-16
1360          *   args[6]: This value communicates the four switch values in block 5
1361          *            of SETUP B, which are only visible to the user when an STP
1362          *            option is installed. These bits may be assigned for an STP
1363          *            device. The four bits are a decimal-encoded binary number.
1364          *            Value between 0-15.
1365          *
1366          * The transmission/receive speeds have mappings for number => bits/s
1367          * which are quite weird. Examples are: 96->3600, 112->9600, 120->19200
1368          *
1369          * Defaults:
1370          *   args[0]: 0
1371          */
1372
1373         if (seq->n_args < 1 || seq->args[0] == 0) {
1374                 screen->flags &= ~TERM_FLAG_INHIBIT_TPARM;
1375                 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "2;1;1;120;120;1;0x");
1376         } else if (seq->args[0] == 1) {
1377                 screen->flags |= TERM_FLAG_INHIBIT_TPARM;
1378                 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "3;1;1;120;120;1;0x");
1379         } else {
1380                 return 0;
1381         }
1382 }
1383
1384 static int screen_DECRPKT(term_screen *screen, const term_seq *seq) {
1385         /*
1386          * DECRPKT - report-key-type
1387          * Response to DECRQKT, we can safely ignore it as we're the one sending
1388          * it to the host.
1389          */
1390
1391         return 0;
1392 }
1393
1394 static int screen_DECRQCRA(term_screen *screen, const term_seq *seq) {
1395         /*
1396          * DECRQCRA - request-checksum-of-rectangular-area
1397          *
1398          * Probably not worth implementing.
1399          */
1400
1401         return 0;
1402 }
1403
1404 static int screen_DECRQDE(term_screen *screen, const term_seq *seq) {
1405         /*
1406          * DECRQDE - request-display-extent
1407          *
1408          * Probably not worth implementing.
1409          */
1410
1411         return 0;
1412 }
1413
1414 static int screen_DECRQKT(term_screen *screen, const term_seq *seq) {
1415         /*
1416          * DECRQKT - request-key-type
1417          *
1418          * Probably not worth implementing.
1419          */
1420
1421         return 0;
1422 }
1423
1424 static int screen_DECRQLP(term_screen *screen, const term_seq *seq) {
1425         /*
1426          * DECRQLP - request-locator-position
1427          * See DECELR for locator-information.
1428          *
1429          * TODO: document and implement
1430          */
1431
1432         return 0;
1433 }
1434
1435 static int screen_DECRQM_ANSI(term_screen *screen, const term_seq *seq) {
1436         /*
1437          * DECRQM_ANSI - request-mode-ansi
1438          * The host sends this control function to find out if a particular mode
1439          * is set or reset. The terminal responds with a report mode function.
1440          * @args[0] contains the mode to query.
1441          *
1442          * Response is DECRPM with the first argument set to the mode that was
1443          * queried, second argument is 0 if mode is invalid, 1 if mode is set,
1444          * 2 if mode is not set (reset), 3 if mode is permanently set and 4 if
1445          * mode is permanently not set (reset):
1446          *   ANSI: ^[ MODE ; VALUE $ y
1447          *   DEC:  ^[ ? MODE ; VALUE $ y
1448          *
1449          * TODO: implement
1450          */
1451
1452         return 0;
1453 }
1454
1455 static int screen_DECRQM_DEC(term_screen *screen, const term_seq *seq) {
1456         /*
1457          * DECRQM_DEC - request-mode-dec
1458          * Same as DECRQM_ANSI but for DEC modes.
1459          *
1460          * TODO: implement
1461          */
1462
1463         return 0;
1464 }
1465
1466 static int screen_DECRQPKFM(term_screen *screen, const term_seq *seq) {
1467         /*
1468          * DECRQPKFM - request-program-key-free-memory
1469          *
1470          * Probably not worth implementing.
1471          */
1472
1473         return 0;
1474 }
1475
1476 static int screen_DECRQPSR(term_screen *screen, const term_seq *seq) {
1477         /*
1478          * DECRQPSR - request-presentation-state-report
1479          *
1480          * Probably not worth implementing.
1481          */
1482
1483         return 0;
1484 }
1485
1486 static int screen_DECRQTSR(term_screen *screen, const term_seq *seq) {
1487         /*
1488          * DECRQTSR - request-terminal-state-report
1489          *
1490          * Probably not worth implementing.
1491          */
1492
1493         return 0;
1494 }
1495
1496 static int screen_DECRQUPSS(term_screen *screen, const term_seq *seq) {
1497         /*
1498          * DECRQUPSS - request-user-preferred-supplemental-set
1499          *
1500          * Probably not worth implementing.
1501          */
1502
1503         return 0;
1504 }
1505
1506 static int screen_DECSACE(term_screen *screen, const term_seq *seq) {
1507         /*
1508          * DECSACE - select-attribute-change-extent
1509          *
1510          * Probably not worth implementing.
1511          */
1512
1513         return 0;
1514 }
1515
1516 static int screen_DECSASD(term_screen *screen, const term_seq *seq) {
1517         /*
1518          * DECSASD - select-active-status-display
1519          *
1520          * Probably not worth implementing.
1521          */
1522
1523         return 0;
1524 }
1525
1526 static int screen_DECSC(term_screen *screen, const term_seq *seq) {
1527         /*
1528          * DECSC - save-cursor
1529          * Save cursor and terminal state so it can be restored later on.
1530          * Saves the following items in the terminal's memory:
1531          *   * Cursor position
1532          *   * Character attributes set by the SGR command
1533          *   * Character sets (G0, G1, G2, or G3) currently in GL and GR
1534          *   * Wrap flag (autowrap or no autowrap)
1535          *   * State of origin mode (DECOM)
1536          *   * Selective erase attribute
1537          *   * Any single shift 2 (SS2) or single shift 3 (SS3) functions sent
1538          */
1539
1540         screen_save_state(screen, &screen->saved);
1541
1542         return 0;
1543 }
1544
1545 static int screen_DECSCA(term_screen *screen, const term_seq *seq) {
1546         /*
1547          * DECSCA - select-character-protection-attribute
1548          * Defines the characters that come after it as erasable or not erasable
1549          * from the screen. The selective erase control functions (DECSED and
1550          * DECSEL) can only erase characters defined as erasable.
1551          *
1552          * @args[0] specifies the new mode. 0 and 2 mark any following character
1553          * as erasable, 1 marks it as not erasable.
1554          *
1555          * Defaults:
1556          *   args[0]: 0
1557          */
1558
1559         unsigned int mode = 0;
1560
1561         if (seq->args[0] > 0)
1562                 mode = seq->args[0];
1563
1564         switch (mode) {
1565         case 0:
1566         case 2:
1567                 screen->state.attr.protect = 0;
1568                 break;
1569         case 1:
1570                 screen->state.attr.protect = 1;
1571                 break;
1572         }
1573
1574         return 0;
1575 }
1576
1577 static int screen_DECSCL(term_screen *screen, const term_seq *seq) {
1578         /*
1579          * DECSCL - select-conformance-level
1580          * Select the terminal's operating level. The factory default is
1581          * level 4 (VT Level 4 mode, 7-bit controls).
1582          * When you change the conformance level, the terminal performs a hard
1583          * reset (RIS).
1584          *
1585          * @args[0] defines the conformance-level, valid values are:
1586          *   61: Level 1 (VT100)
1587          *   62: Level 2 (VT200)
1588          *   63: Level 3 (VT300)
1589          *   64: Level 4 (VT400)
1590          * @args[1] defines the 8bit-mode, valid values are:
1591          *    0: 8-bit controls
1592          *    1: 7-bit controls
1593          *    2: 8-bit controls (same as 0)
1594          *
1595          * If @args[0] is 61, then @args[1] is ignored and 7bit controls are
1596          * enforced.
1597          *
1598          * Defaults:
1599          *   args[0]: 64
1600          *   args[1]: 0
1601          */
1602
1603         unsigned int level = 64, bit = 0;
1604
1605         if (seq->n_args > 0) {
1606                 level = seq->args[0];
1607                 if (seq->n_args > 1)
1608                         bit = seq->args[1];
1609         }
1610
1611         term_screen_hard_reset(screen);
1612
1613         switch (level) {
1614         case 61:
1615                 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT100;
1616                 screen->flags |= TERM_FLAG_7BIT_MODE;
1617                 break;
1618         case 62 ... 69:
1619                 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
1620                 if (bit == 1)
1621                         screen->flags |= TERM_FLAG_7BIT_MODE;
1622                 else
1623                         screen->flags &= ~TERM_FLAG_7BIT_MODE;
1624                 break;
1625         }
1626
1627         return 0;
1628 }
1629
1630 static int screen_DECSCP(term_screen *screen, const term_seq *seq) {
1631         /*
1632          * DECSCP - select-communication-port
1633          *
1634          * Probably not worth implementing.
1635          */
1636
1637         return 0;
1638 }
1639
1640 static int screen_DECSCPP(term_screen *screen, const term_seq *seq) {
1641         /*
1642          * DECSCPP - select-columns-per-page
1643          * Select columns per page. The number of rows is unaffected by this.
1644          * @args[0] selectes the number of columns (width), DEC only defines 80
1645          * and 132, but we allow any integer here. 0 is equivalent to 80.
1646          * Page content is *not* cleared and the cursor is left untouched.
1647          * However, if the page is reduced in width and the cursor would be
1648          * outside the visible region, it's set to the right border. Newly added
1649          * cells are cleared. No data is retained outside the visible region.
1650          *
1651          * Defaults:
1652          *   args[0]: 0
1653          *
1654          * TODO: implement
1655          */
1656
1657         return 0;
1658 }
1659
1660 static int screen_DECSCS(term_screen *screen, const term_seq *seq) {
1661         /*
1662          * DECSCS - select-communication-speed
1663          *
1664          * Probably not worth implementing.
1665          */
1666
1667         return 0;
1668 }
1669
1670 static int screen_DECSCUSR(term_screen *screen, const term_seq *seq) {
1671         /*
1672          * DECSCUSR - set-cursor-style
1673          * This changes the style of the cursor. @args[0] can be one of:
1674          *   0, 1: blinking block
1675          *      2: steady block
1676          *      3: blinking underline
1677          *      4: steady underline
1678          * Changing this setting does _not_ affect the cursor visibility itself.
1679          * Use DECTCEM for that.
1680          *
1681          * Defaults:
1682          *   args[0]: 0
1683          *
1684          * TODO: implement
1685          */
1686
1687         return 0;
1688 }
1689
1690 static int screen_DECSDDT(term_screen *screen, const term_seq *seq) {
1691         /*
1692          * DECSDDT - select-disconnect-delay-time
1693          *
1694          * Probably not worth implementing.
1695          */
1696
1697         return 0;
1698 }
1699
1700 static int screen_DECSDPT(term_screen *screen, const term_seq *seq) {
1701         /*
1702          * DECSDPT - select-digital-printed-data-type
1703          *
1704          * Probably not worth implementing.
1705          */
1706
1707         return 0;
1708 }
1709
1710 static int screen_DECSED(term_screen *screen, const term_seq *seq) {
1711         /*
1712          * DECSED - selective-erase-in-display
1713          * This control function erases some or all of the erasable characters
1714          * in the display. DECSED can only erase characters defined as erasable
1715          * by the DECSCA control function. DECSED works inside or outside the
1716          * scrolling margins.
1717          *
1718          * @args[0] defines which regions are erased. If it is 0, all cells from
1719          * the cursor (inclusive) till the end of the display are erase. If it
1720          * is 1, all cells from the start of the display till the cursor
1721          * (inclusive) are erased. If it is 2, all cells are erased.
1722          *
1723          * Defaults:
1724          *   args[0]: 0
1725          */
1726
1727         unsigned int mode = 0;
1728
1729         if (seq->args[0] > 0)
1730                 mode = seq->args[0];
1731
1732         switch (mode) {
1733         case 0:
1734                 term_page_erase(screen->page,
1735                                 screen->state.cursor_x, screen->state.cursor_y,
1736                                 screen->page->width, screen->page->height,
1737                                 &screen->state.attr, screen->age, true);
1738                 break;
1739         case 1:
1740                 term_page_erase(screen->page,
1741                                 0, 0,
1742                                 screen->state.cursor_x, screen->state.cursor_y,
1743                                 &screen->state.attr, screen->age, true);
1744                 break;
1745         case 2:
1746                 term_page_erase(screen->page,
1747                                 0, 0,
1748                                 screen->page->width, screen->page->height,
1749                                 &screen->state.attr, screen->age, true);
1750                 break;
1751         }
1752
1753         return 0;
1754 }
1755
1756 static int screen_DECSEL(term_screen *screen, const term_seq *seq) {
1757         /*
1758          * DECSEL - selective-erase-in-line
1759          * This control function erases some or all of the erasable characters
1760          * in a single line of text. DECSEL erases only those characters defined
1761          * as erasable by the DECSCA control function. DECSEL works inside or
1762          * outside the scrolling margins.
1763          *
1764          * @args[0] defines the region to be erased. If it is 0, all cells from
1765          * the cursor (inclusive) till the end of the line are erase. If it is
1766          * 1, all cells from the start of the line till the cursor (inclusive)
1767          * are erased. If it is 2, the whole line of the cursor is erased.
1768          *
1769          * Defaults:
1770          *   args[0]: 0
1771          */
1772
1773         unsigned int mode = 0;
1774
1775         if (seq->args[0] > 0)
1776                 mode = seq->args[0];
1777
1778         switch (mode) {
1779         case 0:
1780                 term_page_erase(screen->page,
1781                                 screen->state.cursor_x, screen->state.cursor_y,
1782                                 screen->page->width, screen->state.cursor_y,
1783                                 &screen->state.attr, screen->age, true);
1784                 break;
1785         case 1:
1786                 term_page_erase(screen->page,
1787                                 0, screen->state.cursor_y,
1788                                 screen->state.cursor_x, screen->state.cursor_y,
1789                                 &screen->state.attr, screen->age, true);
1790                 break;
1791         case 2:
1792                 term_page_erase(screen->page,
1793                                 0, screen->state.cursor_y,
1794                                 screen->page->width, screen->state.cursor_y,
1795                                 &screen->state.attr, screen->age, true);
1796                 break;
1797         }
1798
1799         return 0;
1800 }
1801
1802 static int screen_DECSERA(term_screen *screen, const term_seq *seq) {
1803         /*
1804          * DECSERA - selective-erase-rectangular-area
1805          *
1806          * Probably not worth implementing.
1807          */
1808
1809         return 0;
1810 }
1811
1812 static int screen_DECSFC(term_screen *screen, const term_seq *seq) {
1813         /*
1814          * DECSFC - select-flow-control
1815          *
1816          * Probably not worth implementing.
1817          */
1818
1819         return 0;
1820 }
1821
1822 static int screen_DECSKCV(term_screen *screen, const term_seq *seq) {
1823         /*
1824          * DECSKCV - set-key-click-volume
1825          *
1826          * Probably not worth implementing.
1827          */
1828
1829         return 0;
1830 }
1831
1832 static int screen_DECSLCK(term_screen *screen, const term_seq *seq) {
1833         /*
1834          * DECSLCK - set-lock-key-style
1835          *
1836          * Probably not worth implementing.
1837          */
1838
1839         return 0;
1840 }
1841
1842 static int screen_DECSLE(term_screen *screen, const term_seq *seq) {
1843         /*
1844          * DECSLE - select-locator-events
1845          *
1846          * TODO: implement
1847          */
1848
1849         return 0;
1850 }
1851
1852 static int screen_DECSLPP(term_screen *screen, const term_seq *seq) {
1853         /*
1854          * DECSLPP - set-lines-per-page
1855          * Set the number of lines used for the page. @args[0] specifies the
1856          * number of lines to be used. DEC only allows a limited number of
1857          * choices, however, we allow all integers. 0 is equivalent to 24.
1858          *
1859          * Defaults:
1860          *   args[0]: 0
1861          *
1862          * TODO: implement
1863          */
1864
1865         return 0;
1866 }
1867
1868 static int screen_DECSLRM_OR_SC(term_screen *screen, const term_seq *seq) {
1869         /*
1870          * DECSLRM_OR_SC - set-left-and-right-margins or save-cursor
1871          *
1872          * TODO: Detect save-cursor and run it. DECSLRM is not worth
1873          *       implementing.
1874          */
1875
1876         return 0;
1877 }
1878
1879 static int screen_DECSMBV(term_screen *screen, const term_seq *seq) {
1880         /*
1881          * DECSMBV - set-margin-bell-volume
1882          *
1883          * Probably not worth implementing.
1884          */
1885
1886         return 0;
1887 }
1888
1889 static int screen_DECSMKR(term_screen *screen, const term_seq *seq) {
1890         /*
1891          * DECSMKR - select-modifier-key-reporting
1892          *
1893          * Probably not worth implementing.
1894          */
1895
1896         return 0;
1897 }
1898
1899 static int screen_DECSNLS(term_screen *screen, const term_seq *seq) {
1900         /*
1901          * DECSNLS - set-lines-per-screen
1902          *
1903          * Probably not worth implementing.
1904          */
1905
1906         return 0;
1907 }
1908
1909 static int screen_DECSPP(term_screen *screen, const term_seq *seq) {
1910         /*
1911          * DECSPP - set-port-parameter
1912          *
1913          * Probably not worth implementing.
1914          */
1915
1916         return 0;
1917 }
1918
1919 static int screen_DECSPPCS(term_screen *screen, const term_seq *seq) {
1920         /*
1921          * DECSPPCS - select-pro-printer-character-set
1922          *
1923          * Probably not worth implementing.
1924          */
1925
1926         return 0;
1927 }
1928
1929 static int screen_DECSPRTT(term_screen *screen, const term_seq *seq) {
1930         /*
1931          * DECSPRTT - select-printer-type
1932          *
1933          * Probably not worth implementing.
1934          */
1935
1936         return 0;
1937 }
1938
1939 static int screen_DECSR(term_screen *screen, const term_seq *seq) {
1940         /*
1941          * DECSR - secure-reset
1942          *
1943          * Probably not worth implementing.
1944          */
1945
1946         return 0;
1947 }
1948
1949 static int screen_DECSRFR(term_screen *screen, const term_seq *seq) {
1950         /*
1951          * DECSRFR - select-refresh-rate
1952          *
1953          * Probably not worth implementing.
1954          */
1955
1956         return 0;
1957 }
1958
1959 static int screen_DECSSCLS(term_screen *screen, const term_seq *seq) {
1960         /*
1961          * DECSSCLS - set-scroll-speed
1962          *
1963          * Probably not worth implementing.
1964          */
1965
1966         return 0;
1967 }
1968
1969 static int screen_DECSSDT(term_screen *screen, const term_seq *seq) {
1970         /*
1971          * DECSSDT - select-status-display-line-type
1972          *
1973          * Probably not worth implementing.
1974          */
1975
1976         return 0;
1977 }
1978
1979 static int screen_DECSSL(term_screen *screen, const term_seq *seq) {
1980         /*
1981          * DECSSL - select-setup-language
1982          *
1983          * Probably not worth implementing.
1984          */
1985
1986         return 0;
1987 }
1988
1989 static int screen_DECST8C(term_screen *screen, const term_seq *seq) {
1990         /*
1991          * DECST8C - set-tab-at-every-8-columns
1992          * Clear the tab-ruler and reset it to a tab at every 8th column,
1993          * starting at 9 (though, setting a tab at 1 is fine as it has no
1994          * effect).
1995          */
1996
1997         unsigned int i;
1998
1999         for (i = 0; i < screen->page->width; i += 8)
2000                 screen->tabs[i / 8] = 0x1;
2001
2002         return 0;
2003 }
2004
2005 static int screen_DECSTBM(term_screen *screen, const term_seq *seq) {
2006         /*
2007          * DECSTBM - set-top-and-bottom-margins
2008          * This control function sets the top and bottom margins for the current
2009          * page. You cannot perform scrolling outside the margins.
2010          *
2011          * @args[0] defines the top margin, @args[1] defines the bottom margin.
2012          * The bottom margin must be lower than the top-margin.
2013          *
2014          * This call resets the cursor position to 0/0 of the page.
2015          *
2016          * Defaults:
2017          *   args[0]: 1
2018          *   args[1]: last page-line
2019          */
2020
2021         unsigned int top, bottom;
2022
2023         top = 1;
2024         bottom = screen->page->height;
2025
2026         if (seq->args[0] > 0)
2027                 top = seq->args[0];
2028         if (seq->args[1] > 0)
2029                 bottom = seq->args[1];
2030
2031         if (top > screen->page->height)
2032                 top = screen->page->height;
2033         if (bottom > screen->page->height)
2034                 bottom = screen->page->height;
2035
2036         if (top >= bottom || top > screen->page->height || bottom > screen->page->height) {
2037                 top = 1;
2038                 bottom = screen->page->height;
2039         }
2040
2041         term_page_set_scroll_region(screen->page, top - 1, bottom - top + 1);
2042         screen_cursor_clear_wrap(screen);
2043         screen_cursor_set(screen, 0, 0);
2044
2045         return 0;
2046 }
2047
2048 static int screen_DECSTR(term_screen *screen, const term_seq *seq) {
2049         /*
2050          * DECSTR - soft-terminal-reset
2051          * Perform a soft reset to the default values.
2052          */
2053
2054         term_screen_soft_reset(screen);
2055
2056         return 0;
2057 }
2058
2059 static int screen_DECSTRL(term_screen *screen, const term_seq *seq) {
2060         /*
2061          * DECSTRL - set-transmit-rate-limit
2062          *
2063          * Probably not worth implementing.
2064          */
2065
2066         return 0;
2067 }
2068
2069 static int screen_DECSWBV(term_screen *screen, const term_seq *seq) {
2070         /*
2071          * DECSWBV - set-warning-bell-volume
2072          *
2073          * Probably not worth implementing.
2074          */
2075
2076         return 0;
2077 }
2078
2079 static int screen_DECSWL(term_screen *screen, const term_seq *seq) {
2080         /*
2081          * DECSWL - single-width-single-height-line
2082          *
2083          * Probably not worth implementing.
2084          */
2085
2086         return 0;
2087 }
2088
2089 static int screen_DECTID(term_screen *screen, const term_seq *seq) {
2090         /*
2091          * DECTID - select-terminal-id
2092          *
2093          * Probably not worth implementing.
2094          */
2095
2096         return 0;
2097 }
2098
2099 static int screen_DECTME(term_screen *screen, const term_seq *seq) {
2100         /*
2101          * DECTME - terminal-mode-emulation
2102          *
2103          * Probably not worth implementing.
2104          */
2105
2106         return 0;
2107 }
2108
2109 static int screen_DECTST(term_screen *screen, const term_seq *seq) {
2110         /*
2111          * DECTST - invoke-confidence-test
2112          *
2113          * Probably not worth implementing.
2114          */
2115
2116         return 0;
2117 }
2118
2119 static int screen_DL(term_screen *screen, const term_seq *seq) {
2120         /*
2121          * DL - delete-line
2122          * This control function deletes one or more lines in the scrolling
2123          * region, starting with the line that has the cursor. @args[0] defines
2124          * the number of lines to delete. 0 is treated the same as 1.
2125          * As lines are deleted, lines below the cursor and in the scrolling
2126          * region move up. The terminal adds blank lines with no visual
2127          * character attributes at the bottom of the scrolling region. If it is
2128          * greater than the number of lines remaining on the page, DL deletes
2129          * only the remaining lines. DL has no effect outside the scrolling
2130          * margins.
2131          *
2132          * Defaults:
2133          *   args[0]: 1
2134          */
2135
2136         unsigned int num = 1;
2137
2138         if (seq->args[0] > 0)
2139                 num = seq->args[0];
2140
2141         term_page_delete_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2142
2143         return 0;
2144 }
2145
2146 static int screen_DSR_ANSI(term_screen *screen, const term_seq *seq) {
2147         /*
2148          * DSR_ANSI - device-status-report-ansi
2149          *
2150          * TODO: implement
2151          */
2152
2153         return 0;
2154 }
2155
2156 static int screen_DSR_DEC(term_screen *screen, const term_seq *seq) {
2157         /*
2158          * DSR_DEC - device-status-report-dec
2159          *
2160          * TODO: implement
2161          */
2162
2163         return 0;
2164 }
2165
2166 static int screen_ECH(term_screen *screen, const term_seq *seq) {
2167         /*
2168          * ECH - erase-character
2169          * This control function erases one or more characters, from the cursor
2170          * position to the right. ECH clears character attributes from erased
2171          * character positions. ECH works inside or outside the scrolling
2172          * margins.
2173          * @args[0] defines the number of characters to erase. 0 is treated the
2174          * same as 1.
2175          *
2176          * Defaults:
2177          *   args[0]: 1
2178          */
2179
2180         unsigned int num = 1;
2181
2182         if (seq->args[0] > 0)
2183                 num = seq->args[0];
2184
2185         term_page_erase(screen->page,
2186                         screen->state.cursor_x, screen->state.cursor_y,
2187                         screen->state.cursor_x + num, screen->state.cursor_y,
2188                         &screen->state.attr, screen->age, false);
2189
2190         return 0;
2191 }
2192
2193 static int screen_ED(term_screen *screen, const term_seq *seq) {
2194         /*
2195          * ED - erase-in-display
2196          * This control function erases characters from part or all of the
2197          * display. When you erase complete lines, they become single-height,
2198          * single-width lines, with all visual character attributes cleared. ED
2199          * works inside or outside the scrolling margins.
2200          *
2201          * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2202          * till the end of the screen. 1 means from the start of the screen till
2203          * the cursor (inclusive) and 2 means the whole screen.
2204          *
2205          * Defaults:
2206          *   args[0]: 0
2207          */
2208
2209         unsigned int mode = 0;
2210
2211         if (seq->args[0] > 0)
2212                 mode = seq->args[0];
2213
2214         switch (mode) {
2215         case 0:
2216                 term_page_erase(screen->page,
2217                                 screen->state.cursor_x, screen->state.cursor_y,
2218                                 screen->page->width, screen->page->height,
2219                                 &screen->state.attr, screen->age, false);
2220                 break;
2221         case 1:
2222                 term_page_erase(screen->page,
2223                                 0, 0,
2224                                 screen->state.cursor_x, screen->state.cursor_y,
2225                                 &screen->state.attr, screen->age, false);
2226                 break;
2227         case 2:
2228                 term_page_erase(screen->page,
2229                                 0, 0,
2230                                 screen->page->width, screen->page->height,
2231                                 &screen->state.attr, screen->age, false);
2232                 break;
2233         }
2234
2235         return 0;
2236 }
2237
2238 static int screen_EL(term_screen *screen, const term_seq *seq) {
2239         /*
2240          * EL - erase-in-line
2241          * This control function erases characters on the line that has the
2242          * cursor. EL clears all character attributes from erased character
2243          * positions. EL works inside or outside the scrolling margins.
2244          *
2245          * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2246          * till the end of the line. 1 means from the start of the line till the
2247          * cursor (inclusive) and 2 means the whole line.
2248          *
2249          * Defaults:
2250          *   args[0]: 0
2251          */
2252
2253         unsigned int mode = 0;
2254
2255         if (seq->args[0] > 0)
2256                 mode = seq->args[0];
2257
2258         switch (mode) {
2259         case 0:
2260                 term_page_erase(screen->page,
2261                                 screen->state.cursor_x, screen->state.cursor_y,
2262                                 screen->page->width, screen->state.cursor_y,
2263                                 &screen->state.attr, screen->age, false);
2264                 break;
2265         case 1:
2266                 term_page_erase(screen->page,
2267                                 0, screen->state.cursor_y,
2268                                 screen->state.cursor_x, screen->state.cursor_y,
2269                                 &screen->state.attr, screen->age, false);
2270                 break;
2271         case 2:
2272                 term_page_erase(screen->page,
2273                                 0, screen->state.cursor_y,
2274                                 screen->page->width, screen->state.cursor_y,
2275                                 &screen->state.attr, screen->age, false);
2276                 break;
2277         }
2278
2279         return 0;
2280 }
2281
2282 static int screen_ENQ(term_screen *screen, const term_seq *seq) {
2283         /*
2284          * ENQ - enquiry
2285          * Transmit the answerback-string. If none is set, do nothing.
2286          */
2287
2288         if (screen->answerback)
2289                 return screen_write(screen, screen->answerback, strlen(screen->answerback));
2290
2291         return 0;
2292 }
2293
2294 static int screen_EPA(term_screen *screen, const term_seq *seq) {
2295         /*
2296          * EPA - end-of-guarded-area
2297          *
2298          * TODO: What is this?
2299          */
2300
2301         return 0;
2302 }
2303
2304 static int screen_FF(term_screen *screen, const term_seq *seq) {
2305         /*
2306          * FF - form-feed
2307          * This causes the cursor to jump to the next line. It is treated the
2308          * same as LF.
2309          */
2310
2311         return screen_LF(screen, seq);
2312 }
2313
2314 static int screen_HPA(term_screen *screen, const term_seq *seq) {
2315         /*
2316          * HPA - horizontal-position-absolute
2317          * HPA causes the active position to be moved to the n-th horizontal
2318          * position of the active line. If an attempt is made to move the active
2319          * position past the last position on the line, then the active position
2320          * stops at the last position on the line.
2321          *
2322          * @args[0] defines the horizontal position. 0 is treated as 1.
2323          *
2324          * Defaults:
2325          *   args[0]: 1
2326          */
2327
2328         unsigned int num = 1;
2329
2330         if (seq->args[0] > 0)
2331                 num = seq->args[0];
2332
2333         screen_cursor_clear_wrap(screen);
2334         screen_cursor_set(screen, num - 1, screen->state.cursor_y);
2335
2336         return 0;
2337 }
2338
2339 static int screen_HPR(term_screen *screen, const term_seq *seq) {
2340         /*
2341          * HPR - horizontal-position-relative
2342          * HPR causes the active position to be moved to the n-th following
2343          * horizontal position of the active line. If an attempt is made to move
2344          * the active position past the last position on the line, then the
2345          * active position stops at the last position on the line.
2346          *
2347          * @args[0] defines the horizontal position. 0 is treated as 1.
2348          *
2349          * Defaults:
2350          *   args[0]: 1
2351          */
2352
2353         unsigned int num = 1;
2354
2355         if (seq->args[0] > 0)
2356                 num = seq->args[0];
2357
2358         screen_cursor_clear_wrap(screen);
2359         screen_cursor_right(screen, num);
2360
2361         return 0;
2362 }
2363
2364 static int screen_HT(term_screen *screen, const term_seq *seq) {
2365         /*
2366          * HT - horizontal-tab
2367          * Moves the cursor to the next tab stop. If there are no more tab
2368          * stops, the cursor moves to the right margin. HT does not cause text
2369          * to auto wrap.
2370          */
2371
2372         screen_cursor_clear_wrap(screen);
2373         screen_cursor_right_tab(screen, 1);
2374
2375         return 0;
2376 }
2377
2378 static int screen_HTS(term_screen *screen, const term_seq *seq) {
2379         /*
2380          * HTS - horizontal-tab-set
2381          * HTS sets a horizontal tab stop at the column position indicated by
2382          * the value of the active column when the terminal receives an HTS.
2383          *
2384          * Executing an HTS does not effect the other horizontal tab stop
2385          * settings.
2386          */
2387
2388         unsigned int pos;
2389
2390         pos = screen->state.cursor_x;
2391         if (screen->page->width > 0)
2392                 screen->tabs[pos / 8] |= 1U << (pos % 8);
2393
2394         return 0;
2395 }
2396
2397 static int screen_HVP(term_screen *screen, const term_seq *seq) {
2398         /*
2399          * HVP - horizontal-and-vertical-position
2400          * This control function works the same as the cursor position (CUP)
2401          * function. Origin mode (DECOM) selects line numbering and the ability
2402          * to move the cursor into margins.
2403          *
2404          * Defaults:
2405          *   args[0]: 1
2406          *   args[1]: 1
2407          */
2408
2409         return screen_CUP(screen, seq);
2410 }
2411
2412 static int screen_ICH(term_screen *screen, const term_seq *seq) {
2413         /*
2414          * ICH - insert-character
2415          * This control function inserts one or more space (SP) characters
2416          * starting at the cursor position. @args[0] is the number of characters
2417          * to insert. 0 is treated as 1.
2418          *
2419          * The ICH sequence inserts blank characters with the normal
2420          * character attribute. The cursor remains at the beginning of the blank
2421          * characters. Text between the cursor and right margin moves to the
2422          * right. Characters scrolled past the right margin are lost. ICH has no
2423          * effect outside the scrolling margins.
2424          *
2425          * Defaults:
2426          *   args[0]: 1
2427          */
2428
2429         unsigned int num = 1;
2430
2431         if (seq->args[0] > 0)
2432                 num = seq->args[0];
2433
2434         screen_cursor_clear_wrap(screen);
2435         term_page_insert_cells(screen->page, screen->state.cursor_x, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2436
2437         return 0;
2438 }
2439
2440 static int screen_IL(term_screen *screen, const term_seq *seq) {
2441         /*
2442          * IL - insert-line
2443          * This control function inserts one or more blank lines, starting at
2444          * the cursor. @args[0] is the number of lines to insert. 0 is treated
2445          * as 1.
2446          *
2447          * As lines are inserted, lines below the cursor and in the scrolling
2448          * region move down. Lines scrolled off the page are lost. IL has no
2449          * effect outside the page margins.
2450          *
2451          * Defaults:
2452          *   args[0]: 1
2453          */
2454
2455         unsigned int num = 1;
2456
2457         if (seq->args[0] > 0)
2458                 num = seq->args[0];
2459
2460         screen_cursor_clear_wrap(screen);
2461         term_page_insert_lines(screen->page, screen->state.cursor_y, num, &screen->state.attr, screen->age);
2462
2463         return 0;
2464 }
2465
2466 static int screen_IND(term_screen *screen, const term_seq *seq) {
2467         /*
2468          * IND - index
2469          * IND moves the cursor down one line in the same column. If the cursor
2470          * is at the bottom margin, then the screen performs a scroll-up.
2471          */
2472
2473         screen_cursor_down(screen, 1, true);
2474
2475         return 0;
2476 }
2477
2478 static int screen_LF(term_screen *screen, const term_seq *seq) {
2479         /*
2480          * LF - line-feed
2481          * Causes a line feed or a new line operation, depending on the setting
2482          * of line feed/new line mode.
2483          */
2484
2485         screen_cursor_down(screen, 1, true);
2486         if (screen->flags & TERM_FLAG_NEWLINE_MODE)
2487                 screen_cursor_left(screen, screen->state.cursor_x);
2488
2489         return 0;
2490 }
2491
2492 static int screen_LS1R(term_screen *screen, const term_seq *seq) {
2493         /*
2494          * LS1R - locking-shift-1-right
2495          * Map G1 into GR.
2496          */
2497
2498         screen->state.gr = &screen->g1;
2499
2500         return 0;
2501 }
2502
2503 static int screen_LS2(term_screen *screen, const term_seq *seq) {
2504         /*
2505          * LS2 - locking-shift-2
2506          * Map G2 into GL.
2507          */
2508
2509         screen->state.gl = &screen->g2;
2510
2511         return 0;
2512 }
2513
2514 static int screen_LS2R(term_screen *screen, const term_seq *seq) {
2515         /*
2516          * LS2R - locking-shift-2-right
2517          * Map G2 into GR.
2518          */
2519
2520         screen->state.gr = &screen->g2;
2521
2522         return 0;
2523 }
2524
2525 static int screen_LS3(term_screen *screen, const term_seq *seq) {
2526         /*
2527          * LS3 - locking-shift-3
2528          * Map G3 into GL.
2529          */
2530
2531         screen->state.gl = &screen->g3;
2532
2533         return 0;
2534 }
2535
2536 static int screen_LS3R(term_screen *screen, const term_seq *seq) {
2537         /*
2538          * LS3R - locking-shift-3-right
2539          * Map G3 into GR.
2540          */
2541
2542         screen->state.gr = &screen->g3;
2543
2544         return 0;
2545 }
2546
2547 static int screen_MC_ANSI(term_screen *screen, const term_seq *seq) {
2548         /*
2549          * MC_ANSI - media-copy-ansi
2550          *
2551          * Probably not worth implementing.
2552          */
2553
2554         return 0;
2555 }
2556
2557 static int screen_MC_DEC(term_screen *screen, const term_seq *seq) {
2558         /*
2559          * MC_DEC - media-copy-dec
2560          *
2561          * Probably not worth implementing.
2562          */
2563
2564         return 0;
2565 }
2566
2567 static int screen_NEL(term_screen *screen, const term_seq *seq) {
2568         /*
2569          * NEL - next-line
2570          * Moves cursor to first position on next line. If cursor is at bottom
2571          * margin, then screen performs a scroll-up.
2572          */
2573
2574         screen_cursor_clear_wrap(screen);
2575         screen_cursor_down(screen, 1, true);
2576         screen_cursor_set(screen, 0, screen->state.cursor_y);
2577
2578         return 0;
2579 }
2580
2581 static int screen_NP(term_screen *screen, const term_seq *seq) {
2582         /*
2583          * NP - next-page
2584          * This control function moves the cursor forward to the home position
2585          * on one of the following pages in page memory. If there is only one
2586          * page, then the terminal ignores NP.
2587          * If NP tries to move the cursor past the last page in memory, then the
2588          * cursor stops at the last page.
2589          *
2590          * @args[0] defines the number of pages to forward. 0 is treated as 1.
2591          *
2592          * Defaults:
2593          *   args[0]: 1
2594          *
2595          * Probably not worth implementing. We only support a single page.
2596          */
2597
2598         return 0;
2599 }
2600
2601 static int screen_NULL(term_screen *screen, const term_seq *seq) {
2602         /*
2603          * NULL - null
2604          * The NULL operation does nothing. ASCII NULL is always ignored.
2605          */
2606
2607         return 0;
2608 }
2609
2610 static int screen_PP(term_screen *screen, const term_seq *seq) {
2611         /*
2612          * PP - preceding-page
2613          * This control function moves the cursor backward to the home position
2614          * on one of the preceding pages in page memory. If there is only one
2615          * page, then the terminal ignores PP.
2616          * If PP tries to move the cursor back farther than the first page in
2617          * memory, then the cursor stops at the first page.
2618          *
2619          * @args[0] defines the number of pages to go backwards. 0 is treated
2620          * as 1.
2621          *
2622          * Defaults:
2623          *   args[0]: 1
2624          *
2625          * Probably not worth implementing. We only support a single page.
2626          */
2627
2628         return 0;
2629 }
2630
2631 static int screen_PPA(term_screen *screen, const term_seq *seq) {
2632         /*
2633          * PPA - page-position-absolute
2634          * This control function can move the cursor to the corresponding row
2635          * and column on any page in page memory. You select the page by its
2636          * number. If there is only one page, then the terminal ignores PPA.
2637          *
2638          * @args[0] is the number of the page to move the cursor to. If it is
2639          * greater than the number of the last page in memory, then the cursor
2640          * stops at the last page. If it is less than the number of the first
2641          * page, then the cursor stops at the first page.
2642          *
2643          * Defaults:
2644          *   args[0]: 1
2645          *
2646          * Probably not worth implementing. We only support a single page.
2647          */
2648
2649         return 0;
2650 }
2651
2652 static int screen_PPB(term_screen *screen, const term_seq *seq) {
2653         /*
2654          * PPB - page-position-backward
2655          * This control function moves the cursor backward to the corresponding
2656          * row and column on one of the preceding pages in page memory. If there
2657          * is only one page, then the terminal ignores PPB.
2658          *
2659          * @args[0] indicates the number of pages to move the cursor backward.
2660          * If it tries to move the cursor back farther than the first page in
2661          * memory, then the cursor stops at the first page. 0 is treated as 1.
2662          *
2663          * Defaults:
2664          *   args[0]: 1
2665          *
2666          * Probably not worth implementing. We only support a single page.
2667          */
2668
2669         return 0;
2670 }
2671
2672 static int screen_PPR(term_screen *screen, const term_seq *seq) {
2673         /*
2674          * PPR - page-position-relative
2675          * This control function moves the cursor forward to the corresponding
2676          * row and column on one of the following pages in page memory. If there
2677          * is only one page, then the terminal ignores PPR.
2678          *
2679          * @args[0] indicates how many pages to move the cursor forward. If it
2680          * tries to move the cursor beyond the last page in memory, then the
2681          * cursor stops at the last page. 0 is treated as 1.
2682          *
2683          * Defaults:
2684          *   args[0]: 1
2685          *
2686          * Probably not worth implementing. We only support a single page.
2687          */
2688
2689         return 0;
2690 }
2691
2692 static int screen_RC(term_screen *screen, const term_seq *seq) {
2693         /*
2694          * RC - restore-cursor
2695          */
2696
2697         return screen_DECRC(screen, seq);
2698 }
2699
2700 static int screen_REP(term_screen *screen, const term_seq *seq) {
2701         /*
2702          * REP - repeat
2703          * Repeat the preceding graphics-character the given number of times.
2704          * @args[0] specifies how often it shall be repeated. 0 is treated as 1.
2705          *
2706          * Defaults:
2707          *   args[0]: 1
2708          *
2709          * Probably not worth implementing.
2710          */
2711
2712         return 0;
2713 }
2714
2715 static int screen_RI(term_screen *screen, const term_seq *seq) {
2716         /*
2717          * RI - reverse-index
2718          * Moves the cursor up one line in the same column. If the cursor is at
2719          * the top margin, the page scrolls down.
2720          */
2721
2722         screen_cursor_up(screen, 1, true);
2723
2724         return 0;
2725 }
2726
2727 static int screen_RIS(term_screen *screen, const term_seq *seq) {
2728         /*
2729          * RIS - reset-to-initial-state
2730          * This control function causes a nonvolatile memory (NVR) recall to
2731          * occur. RIS replaces all set-up features with their saved settings.
2732          *
2733          * The terminal stores these saved settings in NVR memory. The saved
2734          * setting for a feature is the same as the factory-default setting,
2735          * unless you saved a new setting.
2736          */
2737
2738         term_screen_hard_reset(screen);
2739
2740         return 0;
2741 }
2742
2743 static int screen_RM_ANSI(term_screen *screen, const term_seq *seq) {
2744         /*
2745          * RM_ANSI - reset-mode-ansi
2746          *
2747          * TODO: implement (see VT510rm manual)
2748          */
2749
2750         unsigned int i;
2751
2752         for (i = 0; i < seq->n_args; ++i)
2753                 screen_mode_change_ansi(screen, seq->args[i], false);
2754
2755         return 0;
2756 }
2757
2758 static int screen_RM_DEC(term_screen *screen, const term_seq *seq) {
2759         /*
2760          * RM_DEC - reset-mode-dec
2761          * This is the same as RM_ANSI but for DEC modes.
2762          */
2763
2764         unsigned int i;
2765
2766         for (i = 0; i < seq->n_args; ++i)
2767                 screen_mode_change_dec(screen, seq->args[i], false);
2768
2769         return 0;
2770 }
2771
2772 static int screen_S7C1T(term_screen *screen, const term_seq *seq) {
2773         /*
2774          * S7C1T - set-7bit-c1-terminal
2775          * This causes the terminal to start sending C1 controls as 7bit
2776          * sequences instead of 8bit C1 controls.
2777          * This is ignored if the terminal is below level-2 emulation mode
2778          * (VT100 and below), the terminal already sends 7bit controls then.
2779          */
2780
2781         if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2782                 screen->flags |= TERM_FLAG_7BIT_MODE;
2783
2784         return 0;
2785 }
2786
2787 static int screen_S8C1T(term_screen *screen, const term_seq *seq) {
2788         /*
2789          * S8C1T - set-8bit-c1-terminal
2790          * This causes the terminal to start sending C1 controls as 8bit C1
2791          * control instead of 7bit sequences.
2792          * This is ignored if the terminal is below level-2 emulation mode
2793          * (VT100 and below). The terminal always sends 7bit controls in those
2794          * modes.
2795          */
2796
2797         if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2798                 screen->flags &= ~TERM_FLAG_7BIT_MODE;
2799
2800         return 0;
2801 }
2802
2803 static int screen_SCS(term_screen *screen, const term_seq *seq) {
2804         /*
2805          * SCS - select-character-set
2806          * Designate character sets to G-sets. The mapping from intermediates
2807          * and terminal characters in the escape sequence to G-sets and
2808          * character-sets is non-trivial and implemented separately. See there
2809          * for more information.
2810          * This call simply sets the selected G-set to the desired
2811          * character-set.
2812          */
2813
2814         term_charset *cs = NULL;
2815
2816         /* TODO: support more of them? */
2817         switch (seq->charset) {
2818         case TERM_CHARSET_ISO_LATIN1_SUPPLEMENTAL:
2819         case TERM_CHARSET_ISO_LATIN2_SUPPLEMENTAL:
2820         case TERM_CHARSET_ISO_LATIN5_SUPPLEMENTAL:
2821         case TERM_CHARSET_ISO_GREEK_SUPPLEMENTAL:
2822         case TERM_CHARSET_ISO_HEBREW_SUPPLEMENTAL:
2823         case TERM_CHARSET_ISO_LATIN_CYRILLIC:
2824                 break;
2825
2826         case TERM_CHARSET_DEC_SPECIAL_GRAPHIC:
2827                 cs = &term_dec_special_graphics;
2828                 break;
2829         case TERM_CHARSET_DEC_SUPPLEMENTAL:
2830                 cs = &term_dec_supplemental_graphics;
2831                 break;
2832         case TERM_CHARSET_DEC_TECHNICAL:
2833         case TERM_CHARSET_CYRILLIC_DEC:
2834         case TERM_CHARSET_DUTCH_NRCS:
2835         case TERM_CHARSET_FINNISH_NRCS:
2836         case TERM_CHARSET_FRENCH_NRCS:
2837         case TERM_CHARSET_FRENCH_CANADIAN_NRCS:
2838         case TERM_CHARSET_GERMAN_NRCS:
2839         case TERM_CHARSET_GREEK_DEC:
2840         case TERM_CHARSET_GREEK_NRCS:
2841         case TERM_CHARSET_HEBREW_DEC:
2842         case TERM_CHARSET_HEBREW_NRCS:
2843         case TERM_CHARSET_ITALIAN_NRCS:
2844         case TERM_CHARSET_NORWEGIAN_DANISH_NRCS:
2845         case TERM_CHARSET_PORTUGUESE_NRCS:
2846         case TERM_CHARSET_RUSSIAN_NRCS:
2847         case TERM_CHARSET_SCS_NRCS:
2848         case TERM_CHARSET_SPANISH_NRCS:
2849         case TERM_CHARSET_SWEDISH_NRCS:
2850         case TERM_CHARSET_SWISS_NRCS:
2851         case TERM_CHARSET_TURKISH_DEC:
2852         case TERM_CHARSET_TURKISH_NRCS:
2853                 break;
2854
2855         case TERM_CHARSET_USERPREF_SUPPLEMENTAL:
2856                 break;
2857         }
2858
2859         if (seq->intermediates & TERM_SEQ_FLAG_POPEN)
2860                 screen->g0 = cs ? : &term_unicode_lower;
2861         else if (seq->intermediates & TERM_SEQ_FLAG_PCLOSE)
2862                 screen->g1 = cs ? : &term_unicode_upper;
2863         else if (seq->intermediates & TERM_SEQ_FLAG_MULT)
2864                 screen->g2 = cs ? : &term_unicode_lower;
2865         else if (seq->intermediates & TERM_SEQ_FLAG_PLUS)
2866                 screen->g3 = cs ? : &term_unicode_upper;
2867         else if (seq->intermediates & TERM_SEQ_FLAG_MINUS)
2868                 screen->g1 = cs ? : &term_unicode_upper;
2869         else if (seq->intermediates & TERM_SEQ_FLAG_DOT)
2870                 screen->g2 = cs ? : &term_unicode_lower;
2871         else if (seq->intermediates & TERM_SEQ_FLAG_SLASH)
2872                 screen->g3 = cs ? : &term_unicode_upper;
2873
2874         return 0;
2875 }
2876
2877 static int screen_SD(term_screen *screen, const term_seq *seq) {
2878         /*
2879          * SD - scroll-down
2880          * This control function moves the user window down a specified number
2881          * of lines in page memory.
2882          * @args[0] is the number of lines to move the
2883          * user window up in page memory. New lines appear at the top of the
2884          * display. Old lines disappear at the bottom of the display. You
2885          * cannot pan past the top margin of the current page. 0 is treated
2886          * as 1.
2887          *
2888          * Defaults:
2889          *   args[0]: 1
2890          */
2891
2892         unsigned int num = 1;
2893
2894         if (seq->args[0] > 0)
2895                 num = seq->args[0];
2896
2897         term_page_scroll_down(screen->page, num, &screen->state.attr, screen->age, NULL);
2898
2899         return 0;
2900 }
2901
2902 static int screen_SGR(term_screen *screen, const term_seq *seq) {
2903         /*
2904          * SGR - select-graphics-rendition
2905          */
2906
2907         term_color *dst;
2908         unsigned int i, code;
2909         int v;
2910
2911         if (seq->n_args < 1) {
2912                 zero(screen->state.attr);
2913                 return 0;
2914         }
2915
2916         for (i = 0; i < seq->n_args; ++i) {
2917                 v = seq->args[i];
2918                 switch (v) {
2919                 case 1:
2920                         screen->state.attr.bold = 1;
2921                         break;
2922                 case 3:
2923                         screen->state.attr.italic = 1;
2924                         break;
2925                 case 4:
2926                         screen->state.attr.underline = 1;
2927                         break;
2928                 case 5:
2929                         screen->state.attr.blink = 1;
2930                         break;
2931                 case 7:
2932                         screen->state.attr.inverse = 1;
2933                         break;
2934                 case 8:
2935                         screen->state.attr.hidden = 1;
2936                         break;
2937                 case 22:
2938                         screen->state.attr.bold = 0;
2939                         break;
2940                 case 23:
2941                         screen->state.attr.italic = 0;
2942                         break;
2943                 case 24:
2944                         screen->state.attr.underline = 0;
2945                         break;
2946                 case 25:
2947                         screen->state.attr.blink = 0;
2948                         break;
2949                 case 27:
2950                         screen->state.attr.inverse = 0;
2951                         break;
2952                 case 28:
2953                         screen->state.attr.hidden = 0;
2954                         break;
2955                 case 30 ... 37:
2956                         screen->state.attr.fg.ccode = v - 30 + TERM_CCODE_BLACK;
2957                         break;
2958                 case 39:
2959                         screen->state.attr.fg.ccode = 0;
2960                         break;
2961                 case 40 ... 47:
2962                         screen->state.attr.bg.ccode = v - 40 + TERM_CCODE_BLACK;
2963                         break;
2964                 case 49:
2965                         screen->state.attr.bg.ccode = 0;
2966                         break;
2967                 case 90 ... 97:
2968                         screen->state.attr.fg.ccode = v - 90 + TERM_CCODE_LIGHT_BLACK;
2969                         break;
2970                 case 100 ... 107:
2971                         screen->state.attr.bg.ccode = v - 100 + TERM_CCODE_LIGHT_BLACK;
2972                         break;
2973                 case 38:
2974                         /* fallthrough */
2975                 case 48:
2976
2977                         if (v == 38)
2978                                 dst = &screen->state.attr.fg;
2979                         else
2980                                 dst = &screen->state.attr.bg;
2981
2982                         ++i;
2983                         if (i >= seq->n_args)
2984                                 break;
2985
2986                         switch (seq->args[i]) {
2987                         case 2:
2988                                 /* 24bit-color support */
2989
2990                                 i += 3;
2991                                 if (i >= seq->n_args)
2992                                         break;
2993
2994                                 dst->ccode = TERM_CCODE_RGB;
2995                                 dst->red = (seq->args[i - 2] >= 0) ? seq->args[i - 2] : 0;
2996                                 dst->green = (seq->args[i - 1] >= 0) ? seq->args[i - 1] : 0;
2997                                 dst->blue = (seq->args[i] >= 0) ? seq->args[i] : 0;
2998
2999                                 break;
3000                         case 5:
3001                                 /* 256-color support */
3002
3003                                 ++i;
3004                                 if (i >= seq->n_args || seq->args[i] < 0)
3005                                         break;
3006
3007                                 dst->ccode = TERM_CCODE_256;
3008                                 code = seq->args[i];
3009                                 dst->c256 = code < 256 ? code : 0;
3010
3011                                 break;
3012                         }
3013
3014                         break;
3015                 case -1:
3016                         /* fallthrough */
3017                 case 0:
3018                         zero(screen->state.attr);
3019                         break;
3020                 }
3021         }
3022
3023         return 0;
3024 }
3025
3026 static int screen_SI(term_screen *screen, const term_seq *seq) {
3027         /*
3028          * SI - shift-in
3029          * Map G0 into GL.
3030          */
3031
3032         screen->state.gl = &screen->g0;
3033
3034         return 0;
3035 }
3036
3037 static int screen_SM_ANSI(term_screen *screen, const term_seq *seq) {
3038         /*
3039          * SM_ANSI - set-mode-ansi
3040          *
3041          * TODO: implement
3042          */
3043
3044         unsigned int i;
3045
3046         for (i = 0; i < seq->n_args; ++i)
3047                 screen_mode_change_ansi(screen, seq->args[i], true);
3048
3049         return 0;
3050 }
3051
3052 static int screen_SM_DEC(term_screen *screen, const term_seq *seq) {
3053         /*
3054          * SM_DEC - set-mode-dec
3055          * This is the same as SM_ANSI but for DEC modes.
3056          */
3057
3058         unsigned int i;
3059
3060         for (i = 0; i < seq->n_args; ++i)
3061                 screen_mode_change_dec(screen, seq->args[i], true);
3062
3063         return 0;
3064 }
3065
3066 static int screen_SO(term_screen *screen, const term_seq *seq) {
3067         /*
3068          * SO - shift-out
3069          * Map G1 into GL.
3070          */
3071
3072         screen->state.gl = &screen->g1;
3073
3074         return 0;
3075 }
3076
3077 static int screen_SPA(term_screen *screen, const term_seq *seq) {
3078         /*
3079          * SPA - start-of-protected-area
3080          *
3081          * TODO: What is this?
3082          */
3083
3084         return 0;
3085 }
3086
3087 static int screen_SS2(term_screen *screen, const term_seq *seq) {
3088         /*
3089          * SS2 - single-shift-2
3090          * Temporarily map G2 into GL for the next graphics character.
3091          */
3092
3093         screen->state.glt = &screen->g2;
3094
3095         return 0;
3096 }
3097
3098 static int screen_SS3(term_screen *screen, const term_seq *seq) {
3099         /*
3100          * SS3 - single-shift-3
3101          * Temporarily map G3 into GL for the next graphics character
3102          */
3103
3104         screen->state.glt = &screen->g3;
3105
3106         return 0;
3107 }
3108
3109 static int screen_ST(term_screen *screen, const term_seq *seq) {
3110         /*
3111          * ST - string-terminator
3112          * The string-terminator is usually part of control-sequences and
3113          * handled by the parser. In all other situations it is silently
3114          * ignored.
3115          */
3116
3117         return 0;
3118 }
3119
3120 static int screen_SU(term_screen *screen, const term_seq *seq) {
3121         /*
3122          * SU - scroll-up
3123          * This control function moves the user window up a specified number of
3124          * lines in page memory.
3125          * @args[0] is the number of lines to move the
3126          * user window down in page memory. New lines appear at the bottom of
3127          * the display. Old lines disappear at the top of the display. You
3128          * cannot pan past the bottom margin of the current page. 0 is treated
3129          * as 1.
3130          *
3131          * Defaults:
3132          *   args[0]: 1
3133          */
3134
3135         unsigned int num = 1;
3136
3137         if (seq->args[0] > 0)
3138                 num = seq->args[0];
3139
3140         term_page_scroll_up(screen->page, num, &screen->state.attr, screen->age, screen->history);
3141
3142         return 0;
3143 }
3144
3145 static int screen_SUB(term_screen *screen, const term_seq *seq) {
3146         /*
3147          * SUB - substitute
3148          * Cancel the current control-sequence and print a replacement
3149          * character. Our parser already handles this so all we have to do is
3150          * print the replacement character.
3151          */
3152
3153         static const term_seq rep = {
3154                 .type = TERM_SEQ_GRAPHIC,
3155                 .command = TERM_CMD_GRAPHIC,
3156                 .terminator = 0xfffd,
3157         };
3158
3159         return screen_GRAPHIC(screen, &rep);
3160 }
3161
3162 static int screen_TBC(term_screen *screen, const term_seq *seq) {
3163         /*
3164          * TBC - tab-clear
3165          * This clears tab-stops. If @args[0] is 0, the tab-stop at the current
3166          * cursor position is cleared. If it is 3, all tab stops are cleared.
3167          *
3168          * Defaults:
3169          *   args[0]: 0
3170          */
3171
3172         unsigned int mode = 0, pos;
3173
3174         if (seq->args[0] > 0)
3175                 mode = seq->args[0];
3176
3177         switch (mode) {
3178         case 0:
3179                 pos = screen->state.cursor_x;
3180                 if (screen->page->width > 0)
3181                         screen->tabs[pos / 8] &= ~(1U << (pos % 8));
3182                 break;
3183         case 3:
3184                 if (screen->page->width > 0)
3185                         memset(screen->tabs, 0, (screen->page->width + 7) / 8);
3186                 break;
3187         }
3188
3189         return 0;
3190 }
3191
3192 static int screen_VPA(term_screen *screen, const term_seq *seq) {
3193         /*
3194          * VPA - vertical-line-position-absolute
3195          * VPA causes the active position to be moved to the corresponding
3196          * horizontal position. @args[0] specifies the line to jump to. If an
3197          * attempt is made to move the active position below the last line, then
3198          * the active position stops on the last line. 0 is treated as 1.
3199          *
3200          * Defaults:
3201          *   args[0]: 1
3202          */
3203
3204         unsigned int pos = 1;
3205
3206         if (seq->args[0] > 0)
3207                 pos = seq->args[0];
3208
3209         screen_cursor_clear_wrap(screen);
3210         screen_cursor_set_rel(screen, screen->state.cursor_x, pos - 1);
3211
3212         return 0;
3213 }
3214
3215 static int screen_VPR(term_screen *screen, const term_seq *seq) {
3216         /*
3217          * VPR - vertical-line-position-relative
3218          * VPR causes the active position to be moved to the corresponding
3219          * horizontal position. @args[0] specifies the number of lines to jump
3220          * down relative to the current cursor position. If an attempt is made
3221          * to move the active position below the last line, the active position
3222          * stops at the last line. 0 is treated as 1.
3223          *
3224          * Defaults:
3225          *   args[0]: 1
3226          */
3227
3228         unsigned int num = 1;
3229
3230         if (seq->args[0] > 0)
3231                 num = seq->args[0];
3232
3233         screen_cursor_clear_wrap(screen);
3234         screen_cursor_down(screen, num, false);
3235
3236         return 0;
3237 }
3238
3239 static int screen_VT(term_screen *screen, const term_seq *seq) {
3240         /*
3241          * VT - vertical-tab
3242          * This causes a vertical jump by one line. Terminals treat it exactly
3243          * the same as LF.
3244          */
3245
3246         return screen_LF(screen, seq);
3247 }
3248
3249 static int screen_XTERM_CLLHP(term_screen *screen, const term_seq *seq) {
3250         /*
3251          * XTERM_CLLHP - xterm-cursor-lower-left-hp-bugfix
3252          * Move the cursor to the lower-left corner of the page. This is an HP
3253          * bugfix by xterm.
3254          *
3255          * Probably not worth implementing.
3256          */
3257
3258         return 0;
3259 }
3260
3261 static int screen_XTERM_IHMT(term_screen *screen, const term_seq *seq) {
3262         /*
3263          * XTERM_IHMT - xterm-initiate-highlight-mouse-tracking
3264          *
3265          * Probably not worth implementing.
3266          */
3267
3268         return 0;
3269 }
3270
3271 static int screen_XTERM_MLHP(term_screen *screen, const term_seq *seq) {
3272         /*
3273          * XTERM_MLHP - xterm-memory-lock-hp-bugfix
3274          *
3275          * Probably not worth implementing.
3276          */
3277
3278         return 0;
3279 }
3280
3281 static int screen_XTERM_MUHP(term_screen *screen, const term_seq *seq) {
3282         /*
3283          * XTERM_MUHP - xterm-memory-unlock-hp-bugfix
3284          *
3285          * Probably not worth implementing.
3286          */
3287
3288         return 0;
3289 }
3290
3291 static int screen_XTERM_RPM(term_screen *screen, const term_seq *seq) {
3292         /*
3293          * XTERM_RPM - xterm-restore-private-mode
3294          *
3295          * Probably not worth implementing.
3296          */
3297
3298         return 0;
3299 }
3300
3301 static int screen_XTERM_RRV(term_screen *screen, const term_seq *seq) {
3302         /*
3303          * XTERM_RRV - xterm-reset-resource-value
3304          *
3305          * Probably not worth implementing.
3306          */
3307
3308         return 0;
3309 }
3310
3311 static int screen_XTERM_RTM(term_screen *screen, const term_seq *seq) {
3312         /*
3313          * XTERM_RTM - xterm-reset-title-mode
3314          *
3315          * Probably not worth implementing.
3316          */
3317
3318         return 0;
3319 }
3320
3321 static int screen_XTERM_SACL1(term_screen *screen, const term_seq *seq) {
3322         /*
3323          * XTERM_SACL1 - xterm-set-ansi-conformance-level-1
3324          *
3325          * Probably not worth implementing.
3326          */
3327
3328         return 0;
3329 }
3330
3331 static int screen_XTERM_SACL2(term_screen *screen, const term_seq *seq) {
3332         /*
3333          * XTERM_SACL2 - xterm-set-ansi-conformance-level-2
3334          *
3335          * Probably not worth implementing.
3336          */
3337
3338         return 0;
3339 }
3340
3341 static int screen_XTERM_SACL3(term_screen *screen, const term_seq *seq) {
3342         /*
3343          * XTERM_SACL3 - xterm-set-ansi-conformance-level-3
3344          *
3345          * Probably not worth implementing.
3346          */
3347
3348         return 0;
3349 }
3350
3351 static int screen_XTERM_SDCS(term_screen *screen, const term_seq *seq) {
3352         /*
3353          * XTERM_SDCS - xterm-set-default-character-set
3354          * Select the default character set. We treat this the same as UTF-8 as
3355          * this is our default character set. As we always use UTF-8, this
3356          * becomes as no-op.
3357          */
3358
3359         return 0;
3360 }
3361
3362 static int screen_XTERM_SGFX(term_screen *screen, const term_seq *seq) {
3363         /*
3364          * XTERM_SGFX - xterm-sixel-graphics
3365          *
3366          * Probably not worth implementing.
3367          */
3368
3369         return 0;
3370 }
3371
3372 static int screen_XTERM_SPM(term_screen *screen, const term_seq *seq) {
3373         /*
3374          * XTERM_SPM - xterm-set-private-mode
3375          *
3376          * Probably not worth implementing.
3377          */
3378
3379         return 0;
3380 }
3381
3382 static int screen_XTERM_SRV(term_screen *screen, const term_seq *seq) {
3383         /*
3384          * XTERM_SRV - xterm-set-resource-value
3385          *
3386          * Probably not worth implementing.
3387          */
3388
3389         return 0;
3390 }
3391
3392 static int screen_XTERM_STM(term_screen *screen, const term_seq *seq) {
3393         /*
3394          * XTERM_STM - xterm-set-title-mode
3395          *
3396          * Probably not worth implementing.
3397          */
3398
3399         return 0;
3400 }
3401
3402 static int screen_XTERM_SUCS(term_screen *screen, const term_seq *seq) {
3403         /*
3404          * XTERM_SUCS - xterm-select-utf8-character-set
3405          * Select UTF-8 as character set. This is our default on only character
3406          * set. Hence, this is a no-op.
3407          */
3408
3409         return 0;
3410 }
3411
3412 static int screen_XTERM_WM(term_screen *screen, const term_seq *seq) {
3413         /*
3414          * XTERM_WM - xterm-window-management
3415          *
3416          * Probably not worth implementing.
3417          */
3418
3419         return 0;
3420 }
3421
3422 /*
3423  * Feeding data
3424  * The screen_feed_*() handlers take data from the user and feed it into the
3425  * screen. Once the parser has detected a sequence, we parse the command-type
3426  * and forward it to the command-dispatchers.
3427  */
3428
3429 static int screen_feed_cmd(term_screen *screen, const term_seq *seq) {
3430         switch (seq->command) {
3431         case TERM_CMD_GRAPHIC:
3432                 return screen_GRAPHIC(screen, seq);
3433         case TERM_CMD_BEL:
3434                 return screen_BEL(screen, seq);
3435         case TERM_CMD_BS:
3436                 return screen_BS(screen, seq);
3437         case TERM_CMD_CBT:
3438                 return screen_CBT(screen, seq);
3439         case TERM_CMD_CHA:
3440                 return screen_CHA(screen, seq);
3441         case TERM_CMD_CHT:
3442                 return screen_CHT(screen, seq);
3443         case TERM_CMD_CNL:
3444                 return screen_CNL(screen, seq);
3445         case TERM_CMD_CPL:
3446                 return screen_CPL(screen, seq);
3447         case TERM_CMD_CR:
3448                 return screen_CR(screen, seq);
3449         case TERM_CMD_CUB:
3450                 return screen_CUB(screen, seq);
3451         case TERM_CMD_CUD:
3452                 return screen_CUD(screen, seq);
3453         case TERM_CMD_CUF:
3454                 return screen_CUF(screen, seq);
3455         case TERM_CMD_CUP:
3456                 return screen_CUP(screen, seq);
3457         case TERM_CMD_CUU:
3458                 return screen_CUU(screen, seq);
3459         case TERM_CMD_DA1:
3460                 return screen_DA1(screen, seq);
3461         case TERM_CMD_DA2:
3462                 return screen_DA2(screen, seq);
3463         case TERM_CMD_DA3:
3464                 return screen_DA3(screen, seq);
3465         case TERM_CMD_DC1:
3466                 return screen_DC1(screen, seq);
3467         case TERM_CMD_DC3:
3468                 return screen_DC3(screen, seq);
3469         case TERM_CMD_DCH:
3470                 return screen_DCH(screen, seq);
3471         case TERM_CMD_DECALN:
3472                 return screen_DECALN(screen, seq);
3473         case TERM_CMD_DECANM:
3474                 return screen_DECANM(screen, seq);
3475         case TERM_CMD_DECBI:
3476                 return screen_DECBI(screen, seq);
3477         case TERM_CMD_DECCARA:
3478                 return screen_DECCARA(screen, seq);
3479         case TERM_CMD_DECCRA:
3480                 return screen_DECCRA(screen, seq);
3481         case TERM_CMD_DECDC:
3482                 return screen_DECDC(screen, seq);
3483         case TERM_CMD_DECDHL_BH:
3484                 return screen_DECDHL_BH(screen, seq);
3485         case TERM_CMD_DECDHL_TH:
3486                 return screen_DECDHL_TH(screen, seq);
3487         case TERM_CMD_DECDWL:
3488                 return screen_DECDWL(screen, seq);
3489         case TERM_CMD_DECEFR:
3490                 return screen_DECEFR(screen, seq);
3491         case TERM_CMD_DECELF:
3492                 return screen_DECELF(screen, seq);
3493         case TERM_CMD_DECELR:
3494                 return screen_DECELR(screen, seq);
3495         case TERM_CMD_DECERA:
3496                 return screen_DECERA(screen, seq);
3497         case TERM_CMD_DECFI:
3498                 return screen_DECFI(screen, seq);
3499         case TERM_CMD_DECFRA:
3500                 return screen_DECFRA(screen, seq);
3501         case TERM_CMD_DECIC:
3502                 return screen_DECIC(screen, seq);
3503         case TERM_CMD_DECID:
3504                 return screen_DECID(screen, seq);
3505         case TERM_CMD_DECINVM:
3506                 return screen_DECINVM(screen, seq);
3507         case TERM_CMD_DECKBD:
3508                 return screen_DECKBD(screen, seq);
3509         case TERM_CMD_DECKPAM:
3510                 return screen_DECKPAM(screen, seq);
3511         case TERM_CMD_DECKPNM:
3512                 return screen_DECKPNM(screen, seq);
3513         case TERM_CMD_DECLFKC:
3514                 return screen_DECLFKC(screen, seq);
3515         case TERM_CMD_DECLL:
3516                 return screen_DECLL(screen, seq);
3517         case TERM_CMD_DECLTOD:
3518                 return screen_DECLTOD(screen, seq);
3519         case TERM_CMD_DECPCTERM:
3520                 return screen_DECPCTERM(screen, seq);
3521         case TERM_CMD_DECPKA:
3522                 return screen_DECPKA(screen, seq);
3523         case TERM_CMD_DECPKFMR:
3524                 return screen_DECPKFMR(screen, seq);
3525         case TERM_CMD_DECRARA:
3526                 return screen_DECRARA(screen, seq);
3527         case TERM_CMD_DECRC:
3528                 return screen_DECRC(screen, seq);
3529         case TERM_CMD_DECREQTPARM:
3530                 return screen_DECREQTPARM(screen, seq);
3531         case TERM_CMD_DECRPKT:
3532                 return screen_DECRPKT(screen, seq);
3533         case TERM_CMD_DECRQCRA:
3534                 return screen_DECRQCRA(screen, seq);
3535         case TERM_CMD_DECRQDE:
3536                 return screen_DECRQDE(screen, seq);
3537         case TERM_CMD_DECRQKT:
3538                 return screen_DECRQKT(screen, seq);
3539         case TERM_CMD_DECRQLP:
3540                 return screen_DECRQLP(screen, seq);
3541         case TERM_CMD_DECRQM_ANSI:
3542                 return screen_DECRQM_ANSI(screen, seq);
3543         case TERM_CMD_DECRQM_DEC:
3544                 return screen_DECRQM_DEC(screen, seq);
3545         case TERM_CMD_DECRQPKFM:
3546                 return screen_DECRQPKFM(screen, seq);
3547         case TERM_CMD_DECRQPSR:
3548                 return screen_DECRQPSR(screen, seq);
3549         case TERM_CMD_DECRQTSR:
3550                 return screen_DECRQTSR(screen, seq);
3551         case TERM_CMD_DECRQUPSS:
3552                 return screen_DECRQUPSS(screen, seq);
3553         case TERM_CMD_DECSACE:
3554                 return screen_DECSACE(screen, seq);
3555         case TERM_CMD_DECSASD:
3556                 return screen_DECSASD(screen, seq);
3557         case TERM_CMD_DECSC:
3558                 return screen_DECSC(screen, seq);
3559         case TERM_CMD_DECSCA:
3560                 return screen_DECSCA(screen, seq);
3561         case TERM_CMD_DECSCL:
3562                 return screen_DECSCL(screen, seq);
3563         case TERM_CMD_DECSCP:
3564                 return screen_DECSCP(screen, seq);
3565         case TERM_CMD_DECSCPP:
3566                 return screen_DECSCPP(screen, seq);
3567         case TERM_CMD_DECSCS:
3568                 return screen_DECSCS(screen, seq);
3569         case TERM_CMD_DECSCUSR:
3570                 return screen_DECSCUSR(screen, seq);
3571         case TERM_CMD_DECSDDT:
3572                 return screen_DECSDDT(screen, seq);
3573         case TERM_CMD_DECSDPT:
3574                 return screen_DECSDPT(screen, seq);
3575         case TERM_CMD_DECSED:
3576                 return screen_DECSED(screen, seq);
3577         case TERM_CMD_DECSEL:
3578                 return screen_DECSEL(screen, seq);
3579         case TERM_CMD_DECSERA:
3580                 return screen_DECSERA(screen, seq);
3581         case TERM_CMD_DECSFC:
3582                 return screen_DECSFC(screen, seq);
3583         case TERM_CMD_DECSKCV:
3584                 return screen_DECSKCV(screen, seq);
3585         case TERM_CMD_DECSLCK:
3586                 return screen_DECSLCK(screen, seq);
3587         case TERM_CMD_DECSLE:
3588                 return screen_DECSLE(screen, seq);
3589         case TERM_CMD_DECSLPP:
3590                 return screen_DECSLPP(screen, seq);
3591         case TERM_CMD_DECSLRM_OR_SC:
3592                 return screen_DECSLRM_OR_SC(screen, seq);
3593         case TERM_CMD_DECSMBV:
3594                 return screen_DECSMBV(screen, seq);
3595         case TERM_CMD_DECSMKR:
3596                 return screen_DECSMKR(screen, seq);
3597         case TERM_CMD_DECSNLS:
3598                 return screen_DECSNLS(screen, seq);
3599         case TERM_CMD_DECSPP:
3600                 return screen_DECSPP(screen, seq);
3601         case TERM_CMD_DECSPPCS:
3602                 return screen_DECSPPCS(screen, seq);
3603         case TERM_CMD_DECSPRTT:
3604                 return screen_DECSPRTT(screen, seq);
3605         case TERM_CMD_DECSR:
3606                 return screen_DECSR(screen, seq);
3607         case TERM_CMD_DECSRFR:
3608                 return screen_DECSRFR(screen, seq);
3609         case TERM_CMD_DECSSCLS:
3610                 return screen_DECSSCLS(screen, seq);
3611         case TERM_CMD_DECSSDT:
3612                 return screen_DECSSDT(screen, seq);
3613         case TERM_CMD_DECSSL:
3614                 return screen_DECSSL(screen, seq);
3615         case TERM_CMD_DECST8C:
3616                 return screen_DECST8C(screen, seq);
3617         case TERM_CMD_DECSTBM:
3618                 return screen_DECSTBM(screen, seq);
3619         case TERM_CMD_DECSTR:
3620                 return screen_DECSTR(screen, seq);
3621         case TERM_CMD_DECSTRL:
3622                 return screen_DECSTRL(screen, seq);
3623         case TERM_CMD_DECSWBV:
3624                 return screen_DECSWBV(screen, seq);
3625         case TERM_CMD_DECSWL:
3626                 return screen_DECSWL(screen, seq);
3627         case TERM_CMD_DECTID:
3628                 return screen_DECTID(screen, seq);
3629         case TERM_CMD_DECTME:
3630                 return screen_DECTME(screen, seq);
3631         case TERM_CMD_DECTST:
3632                 return screen_DECTST(screen, seq);
3633         case TERM_CMD_DL:
3634                 return screen_DL(screen, seq);
3635         case TERM_CMD_DSR_ANSI:
3636                 return screen_DSR_ANSI(screen, seq);
3637         case TERM_CMD_DSR_DEC:
3638                 return screen_DSR_DEC(screen, seq);
3639         case TERM_CMD_ECH:
3640                 return screen_ECH(screen, seq);
3641         case TERM_CMD_ED:
3642                 return screen_ED(screen, seq);
3643         case TERM_CMD_EL:
3644                 return screen_EL(screen, seq);
3645         case TERM_CMD_ENQ:
3646                 return screen_ENQ(screen, seq);
3647         case TERM_CMD_EPA:
3648                 return screen_EPA(screen, seq);
3649         case TERM_CMD_FF:
3650                 return screen_FF(screen, seq);
3651         case TERM_CMD_HPA:
3652                 return screen_HPA(screen, seq);
3653         case TERM_CMD_HPR:
3654                 return screen_HPR(screen, seq);
3655         case TERM_CMD_HT:
3656                 return screen_HT(screen, seq);
3657         case TERM_CMD_HTS:
3658                 return screen_HTS(screen, seq);
3659         case TERM_CMD_HVP:
3660                 return screen_HVP(screen, seq);
3661         case TERM_CMD_ICH:
3662                 return screen_ICH(screen, seq);
3663         case TERM_CMD_IL:
3664                 return screen_IL(screen, seq);
3665         case TERM_CMD_IND:
3666                 return screen_IND(screen, seq);
3667         case TERM_CMD_LF:
3668                 return screen_LF(screen, seq);
3669         case TERM_CMD_LS1R:
3670                 return screen_LS1R(screen, seq);
3671         case TERM_CMD_LS2:
3672                 return screen_LS2(screen, seq);
3673         case TERM_CMD_LS2R:
3674                 return screen_LS2R(screen, seq);
3675         case TERM_CMD_LS3:
3676                 return screen_LS3(screen, seq);
3677         case TERM_CMD_LS3R:
3678                 return screen_LS3R(screen, seq);
3679         case TERM_CMD_MC_ANSI:
3680                 return screen_MC_ANSI(screen, seq);
3681         case TERM_CMD_MC_DEC:
3682                 return screen_MC_DEC(screen, seq);
3683         case TERM_CMD_NEL:
3684                 return screen_NEL(screen, seq);
3685         case TERM_CMD_NP:
3686                 return screen_NP(screen, seq);
3687         case TERM_CMD_NULL:
3688                 return screen_NULL(screen, seq);
3689         case TERM_CMD_PP:
3690                 return screen_PP(screen, seq);
3691         case TERM_CMD_PPA:
3692                 return screen_PPA(screen, seq);
3693         case TERM_CMD_PPB:
3694                 return screen_PPB(screen, seq);
3695         case TERM_CMD_PPR:
3696                 return screen_PPR(screen, seq);
3697         case TERM_CMD_RC:
3698                 return screen_RC(screen, seq);
3699         case TERM_CMD_REP:
3700                 return screen_REP(screen, seq);
3701         case TERM_CMD_RI:
3702                 return screen_RI(screen, seq);
3703         case TERM_CMD_RIS:
3704                 return screen_RIS(screen, seq);
3705         case TERM_CMD_RM_ANSI:
3706                 return screen_RM_ANSI(screen, seq);
3707         case TERM_CMD_RM_DEC:
3708                 return screen_RM_DEC(screen, seq);
3709         case TERM_CMD_S7C1T:
3710                 return screen_S7C1T(screen, seq);
3711         case TERM_CMD_S8C1T:
3712                 return screen_S8C1T(screen, seq);
3713         case TERM_CMD_SCS:
3714                 return screen_SCS(screen, seq);
3715         case TERM_CMD_SD:
3716                 return screen_SD(screen, seq);
3717         case TERM_CMD_SGR:
3718                 return screen_SGR(screen, seq);
3719         case TERM_CMD_SI:
3720                 return screen_SI(screen, seq);
3721         case TERM_CMD_SM_ANSI:
3722                 return screen_SM_ANSI(screen, seq);
3723         case TERM_CMD_SM_DEC:
3724                 return screen_SM_DEC(screen, seq);
3725         case TERM_CMD_SO:
3726                 return screen_SO(screen, seq);
3727         case TERM_CMD_SPA:
3728                 return screen_SPA(screen, seq);
3729         case TERM_CMD_SS2:
3730                 return screen_SS2(screen, seq);
3731         case TERM_CMD_SS3:
3732                 return screen_SS3(screen, seq);
3733         case TERM_CMD_ST:
3734                 return screen_ST(screen, seq);
3735         case TERM_CMD_SU:
3736                 return screen_SU(screen, seq);
3737         case TERM_CMD_SUB:
3738                 return screen_SUB(screen, seq);
3739         case TERM_CMD_TBC:
3740                 return screen_TBC(screen, seq);
3741         case TERM_CMD_VPA:
3742                 return screen_VPA(screen, seq);
3743         case TERM_CMD_VPR:
3744                 return screen_VPR(screen, seq);
3745         case TERM_CMD_VT:
3746                 return screen_VT(screen, seq);
3747         case TERM_CMD_XTERM_CLLHP:
3748                 return screen_XTERM_CLLHP(screen, seq);
3749         case TERM_CMD_XTERM_IHMT:
3750                 return screen_XTERM_IHMT(screen, seq);
3751         case TERM_CMD_XTERM_MLHP:
3752                 return screen_XTERM_MLHP(screen, seq);
3753         case TERM_CMD_XTERM_MUHP:
3754                 return screen_XTERM_MUHP(screen, seq);
3755         case TERM_CMD_XTERM_RPM:
3756                 return screen_XTERM_RPM(screen, seq);
3757         case TERM_CMD_XTERM_RRV:
3758                 return screen_XTERM_RRV(screen, seq);
3759         case TERM_CMD_XTERM_RTM:
3760                 return screen_XTERM_RTM(screen, seq);
3761         case TERM_CMD_XTERM_SACL1:
3762                 return screen_XTERM_SACL1(screen, seq);
3763         case TERM_CMD_XTERM_SACL2:
3764                 return screen_XTERM_SACL2(screen, seq);
3765         case TERM_CMD_XTERM_SACL3:
3766                 return screen_XTERM_SACL3(screen, seq);
3767         case TERM_CMD_XTERM_SDCS:
3768                 return screen_XTERM_SDCS(screen, seq);
3769         case TERM_CMD_XTERM_SGFX:
3770                 return screen_XTERM_SGFX(screen, seq);
3771         case TERM_CMD_XTERM_SPM:
3772                 return screen_XTERM_SPM(screen, seq);
3773         case TERM_CMD_XTERM_SRV:
3774                 return screen_XTERM_SRV(screen, seq);
3775         case TERM_CMD_XTERM_STM:
3776                 return screen_XTERM_STM(screen, seq);
3777         case TERM_CMD_XTERM_SUCS:
3778                 return screen_XTERM_SUCS(screen, seq);
3779         case TERM_CMD_XTERM_WM:
3780                 return screen_XTERM_WM(screen, seq);
3781         }
3782
3783         return 0;
3784 }
3785
3786 unsigned int term_screen_get_width(term_screen *screen) {
3787         assert_return(screen, -EINVAL);
3788
3789         return screen->page->width;
3790 }
3791
3792 unsigned int term_screen_get_height(term_screen *screen) {
3793         assert_return(screen, -EINVAL);
3794
3795         return screen->page->height;
3796 }
3797
3798 uint64_t term_screen_get_age(term_screen *screen) {
3799         assert_return(screen, 0);
3800
3801         return screen->age;
3802 }
3803
3804 int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) {
3805         uint32_t *ucs4_str;
3806         size_t i, j, ucs4_len;
3807         const term_seq *seq;
3808         int r;
3809
3810         assert_return(screen, -EINVAL);
3811
3812         ++screen->age;
3813
3814         /* Feed bytes into utf8 decoder and handle parsed ucs4 chars. We always
3815          * treat data as UTF-8, but the parser makes sure to fall back to raw
3816          * 8bit mode if the stream is not valid UTF-8. This should be more than
3817          * enough to support old 7bit/8bit modes. */
3818         for (i = 0; i < size; ++i) {
3819                 ucs4_len = term_utf8_decode(&screen->utf8, &ucs4_str, in[i]);
3820                 for (j = 0; j < ucs4_len; ++j) {
3821                         r = term_parser_feed(screen->parser, &seq, ucs4_str[j]);
3822                         if (r < 0) {
3823                                 return r;
3824                         } else if (r != TERM_SEQ_NONE) {
3825                                 r = screen_feed_cmd(screen, seq);
3826                                 if (r < 0)
3827                                         return r;
3828                         }
3829                 }
3830         }
3831
3832         return 0;
3833 }
3834
3835 static char *screen_map_key(term_screen *screen,
3836                             char *p,
3837                             const uint32_t *keysyms,
3838                             size_t n_syms,
3839                             uint32_t ascii,
3840                             const uint32_t *ucs4,
3841                             unsigned int mods) {
3842         char ch, ch2, ch_mods;
3843         uint32_t v;
3844         size_t i;
3845
3846         /* TODO: All these key-mappings need to be verified. Public information
3847          * on those mappings is pretty scarce and every emulator seems to do it
3848          * slightly differently.
3849          * A lot of mappings are also missing. */
3850
3851         if (n_syms < 1)
3852                 return p;
3853
3854         if (n_syms == 1)
3855                 v = keysyms[0];
3856         else
3857                 v = XKB_KEY_NoSymbol;
3858
3859         /* In some mappings, the modifiers are encoded as CSI parameters. The
3860          * encoding is rather arbitrary, but seems to work. */
3861         ch_mods = 0;
3862         switch (mods & (TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT | TERM_KBDMOD_CTRL)) {
3863         case TERM_KBDMOD_SHIFT:
3864                 ch_mods = '2';
3865                 break;
3866         case TERM_KBDMOD_ALT:
3867                 ch_mods = '3';
3868                 break;
3869         case TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3870                 ch_mods = '4';
3871                 break;
3872         case TERM_KBDMOD_CTRL:
3873                 ch_mods = '5';
3874                 break;
3875         case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT:
3876                 ch_mods = '6';
3877                 break;
3878         case TERM_KBDMOD_CTRL | TERM_KBDMOD_ALT:
3879                 ch_mods = '7';
3880                 break;
3881         case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
3882                 ch_mods = '8';
3883                 break;
3884         }
3885
3886         /* A user might actually use multiple layouts for keyboard
3887          * input. @keysyms[0] contains the actual keysym that the user
3888          * used. But if this keysym is not in the ascii range, the
3889          * input handler does check all other layouts that the user
3890          * specified whether one of them maps the key to some ASCII
3891          * keysym and provides this via @ascii. We always use the real
3892          * keysym except when handling CTRL+<XY> shortcuts we use the
3893          * ascii keysym. This is for compatibility to xterm et. al. so
3894          * ctrl+c always works regardless of the currently active
3895          * keyboard layout. But if no ascii-sym is found, we still use
3896          * the real keysym. */
3897         if (ascii == XKB_KEY_NoSymbol)
3898                 ascii = v;
3899
3900         /* map CTRL+<ascii> */
3901         if (mods & TERM_KBDMOD_CTRL) {
3902                 switch (ascii) {
3903                 case 0x60 ... 0x7e:
3904                         /* Right hand side is mapped to the left and then
3905                          * treated equally. Fall through to left-hand side.. */
3906                         ascii -= 0x20;
3907                 case 0x20 ... 0x5f:
3908                         /* Printable ASCII is mapped 1-1 in XKB and in
3909                          * combination with CTRL bit 7 is flipped. This
3910                          * is equivalent to the caret-notation. */
3911                         *p++ = ascii ^ 0x40;
3912                         return p;
3913                 }
3914         }
3915
3916         /* map cursor keys */
3917         ch = 0;
3918         switch (v) {
3919         case XKB_KEY_Up:
3920                 ch = 'A';
3921                 break;
3922         case XKB_KEY_Down:
3923                 ch = 'B';
3924                 break;
3925         case XKB_KEY_Right:
3926                 ch = 'C';
3927                 break;
3928         case XKB_KEY_Left:
3929                 ch = 'D';
3930                 break;
3931         case XKB_KEY_Home:
3932                 ch = 'H';
3933                 break;
3934         case XKB_KEY_End:
3935                 ch = 'F';
3936                 break;
3937         }
3938         if (ch) {
3939                 *p++ = 0x1b;
3940                 if (screen->flags & TERM_FLAG_CURSOR_KEYS)
3941                         *p++ = 'O';
3942                 else
3943                         *p++ = '[';
3944                 if (ch_mods) {
3945                         *p++ = '1';
3946                         *p++ = ';';
3947                         *p++ = ch_mods;
3948                 }
3949                 *p++ = ch;
3950                 return p;
3951         }
3952
3953         /* map action keys */
3954         ch = 0;
3955         switch (v) {
3956         case XKB_KEY_Find:
3957                 ch = '1';
3958                 break;
3959         case XKB_KEY_Insert:
3960                 ch = '2';
3961                 break;
3962         case XKB_KEY_Delete:
3963                 ch = '3';
3964                 break;
3965         case XKB_KEY_Select:
3966                 ch = '4';
3967                 break;
3968         case XKB_KEY_Page_Up:
3969                 ch = '5';
3970                 break;
3971         case XKB_KEY_Page_Down:
3972                 ch = '6';
3973                 break;
3974         }
3975         if (ch) {
3976                 *p++ = 0x1b;
3977                 *p++ = '[';
3978                 *p++ = ch;
3979                 if (ch_mods) {
3980                         *p++ = ';';
3981                         *p++ = ch_mods;
3982                 }
3983                 *p++ = '~';
3984                 return p;
3985         }
3986
3987         /* map lower function keys */
3988         ch = 0;
3989         switch (v) {
3990         case XKB_KEY_F1:
3991                 ch = 'P';
3992                 break;
3993         case XKB_KEY_F2:
3994                 ch = 'Q';
3995                 break;
3996         case XKB_KEY_F3:
3997                 ch = 'R';
3998                 break;
3999         case XKB_KEY_F4:
4000                 ch = 'S';
4001                 break;
4002         }
4003         if (ch) {
4004                 if (ch_mods) {
4005                         *p++ = 0x1b;
4006                         *p++ = '[';
4007                         *p++ = '1';
4008                         *p++ = ';';
4009                         *p++ = ch_mods;
4010                         *p++ = ch;
4011                 } else {
4012                         *p++ = 0x1b;
4013                         *p++ = 'O';
4014                         *p++ = ch;
4015                 }
4016
4017                 return p;
4018         }
4019
4020         /* map upper function keys */
4021         ch = 0;
4022         ch2 = 0;
4023         switch (v) {
4024         case XKB_KEY_F5:
4025                 ch = '1';
4026                 ch2 = '5';
4027                 break;
4028         case XKB_KEY_F6:
4029                 ch = '1';
4030                 ch2 = '7';
4031                 break;
4032         case XKB_KEY_F7:
4033                 ch = '1';
4034                 ch2 = '8';
4035                 break;
4036         case XKB_KEY_F8:
4037                 ch = '1';
4038                 ch2 = '9';
4039                 break;
4040         case XKB_KEY_F9:
4041                 ch = '2';
4042                 ch2 = '0';
4043                 break;
4044         case XKB_KEY_F10:
4045                 ch = '2';
4046                 ch2 = '1';
4047                 break;
4048         case XKB_KEY_F11:
4049                 ch = '2';
4050                 ch2 = '2';
4051                 break;
4052         case XKB_KEY_F12:
4053                 ch = '2';
4054                 ch2 = '3';
4055                 break;
4056         }
4057         if (ch) {
4058                 *p++ = 0x1b;
4059                 *p++ = '[';
4060                 *p++ = ch;
4061                 if (ch2)
4062                         *p++ = ch2;
4063                 if (ch_mods) {
4064                         *p++ = ';';
4065                         *p++ = ch_mods;
4066                 }
4067                 *p++ = '~';
4068                 return p;
4069         }
4070
4071         /* map special keys */
4072         switch (v) {
4073         case 0xff08: /* XKB_KEY_BackSpace */
4074         case 0xff09: /* XKB_KEY_Tab */
4075         case 0xff0a: /* XKB_KEY_Linefeed */
4076         case 0xff0b: /* XKB_KEY_Clear */
4077         case 0xff15: /* XKB_KEY_Sys_Req */
4078         case 0xff1b: /* XKB_KEY_Escape */
4079         case 0xffff: /* XKB_KEY_Delete */
4080                 *p++ = v - 0xff00;
4081                 return p;
4082         case 0xff13: /* XKB_KEY_Pause */
4083                 /* TODO: What should we do with this key?
4084                  * Sending XOFF is awful as there is no simple
4085                  * way on modern keyboards to send XON again.
4086                  * If someone wants this, we can re-eanble
4087                  * optionally. */
4088                 return p;
4089         case 0xff14: /* XKB_KEY_Scroll_Lock */
4090                 /* TODO: What should we do on scroll-lock?
4091                  * Sending 0x14 is what the specs say but it is
4092                  * not used today the way most users would
4093                  * expect so we disable it. If someone wants
4094                  * this, we can re-enable it (optionally). */
4095                 return p;
4096         case XKB_KEY_Return:
4097                 *p++ = 0x0d;
4098                 if (screen->flags & TERM_FLAG_NEWLINE_MODE)
4099                         *p++ = 0x0a;
4100                 return p;
4101         case XKB_KEY_ISO_Left_Tab:
4102                 *p++ = 0x09;
4103                 return p;
4104         }
4105
4106         /* map unicode keys */
4107         for (i = 0; i < n_syms; ++i)
4108                 p += term_utf8_encode(p, ucs4[i]);
4109
4110         return p;
4111 }
4112
4113 int term_screen_feed_keyboard(term_screen *screen,
4114                               const uint32_t *keysyms,
4115                               size_t n_syms,
4116                               uint32_t ascii,
4117                               const uint32_t *ucs4,
4118                               unsigned int mods) {
4119         _cleanup_free_ char *dyn = NULL;
4120         static const size_t padding = 1;
4121         char buf[128], *start, *p;
4122
4123         assert_return(screen, -EINVAL);
4124
4125         /* allocate buffer if too small */
4126         start = buf;
4127         if (4 * n_syms + padding > sizeof(buf)) {
4128                 dyn = malloc(4 * n_syms + padding);
4129                 if (!dyn)
4130                         return -ENOMEM;
4131
4132                 start = dyn;
4133         }
4134
4135         /* reserve prefix space */
4136         start += padding;
4137         p = start;
4138
4139         p = screen_map_key(screen, p, keysyms, n_syms, ascii, ucs4, mods);
4140         if (!p || p - start < 1)
4141                 return 0;
4142
4143         /* The ALT modifier causes ESC to be prepended to any key-stroke. We
4144          * already accounted for that buffer space above, so simply prepend it
4145          * here.
4146          * TODO: is altSendsEscape a suitable default? What are the semantics
4147          * exactly? Is it used in C0/C1 conversion? Is it prepended if there
4148          * already is an escape character? */
4149         if (mods & TERM_KBDMOD_ALT && *start != 0x1b)
4150                 *--start = 0x1b;
4151
4152         /* turn C0 into C1 */
4153         if (!(screen->flags & TERM_FLAG_7BIT_MODE) && p - start >= 2)
4154                 if (start[0] == 0x1b && start[1] >= 0x40 && start[1] <= 0x5f)
4155                         *++start ^= 0x40;
4156
4157         return screen_write(screen, start, p - start);
4158 }
4159
4160 int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) {
4161         unsigned int i;
4162         uint8_t *t;
4163         int r;
4164
4165         assert_return(screen, -EINVAL);
4166
4167         r = term_page_reserve(screen->page_main, x, y, &screen->state.attr, screen->age);
4168         if (r < 0)
4169                 return r;
4170
4171         r = term_page_reserve(screen->page_alt, x, y, &screen->state.attr, screen->age);
4172         if (r < 0)
4173                 return r;
4174
4175         if (x > screen->n_tabs) {
4176                 t = realloc(screen->tabs, (x + 7) / 8);
4177                 if (!t)
4178                         return -ENOMEM;
4179
4180                 screen->tabs = t;
4181                 screen->n_tabs = x;
4182         }
4183
4184         for (i = (screen->page->width + 7) / 8 * 8; i < x; i += 8)
4185                 screen->tabs[i / 8] = 0x1;
4186
4187         term_page_resize(screen->page_main, x, y, &screen->state.attr, screen->age, screen->history);
4188         term_page_resize(screen->page_alt, x, y, &screen->state.attr, screen->age, NULL);
4189
4190         screen->state.cursor_x = screen_clamp_x(screen, screen->state.cursor_x);
4191         screen->state.cursor_y = screen_clamp_x(screen, screen->state.cursor_y);
4192         screen_cursor_clear_wrap(screen);
4193
4194         return 0;
4195 }
4196
4197 void term_screen_soft_reset(term_screen *screen) {
4198         unsigned int i;
4199
4200         assert(screen);
4201
4202         screen->g0 = &term_unicode_lower;
4203         screen->g1 = &term_unicode_upper;
4204         screen->g2 = &term_unicode_lower;
4205         screen->g3 = &term_unicode_upper;
4206         screen->state.attr = screen->default_attr;
4207         screen->state.gl = &screen->g0;
4208         screen->state.gr = &screen->g1;
4209         screen->state.glt = NULL;
4210         screen->state.grt = NULL;
4211         screen->state.auto_wrap = 0;
4212         screen->state.origin_mode = 0;
4213
4214         screen->saved = screen->state;
4215         screen->saved.cursor_x = 0;
4216         screen->saved.cursor_y = 0;
4217         screen->saved_alt = screen->saved;
4218
4219         screen->page = screen->page_main;
4220         screen->history = screen->history_main;
4221         screen->flags = TERM_FLAG_7BIT_MODE;
4222         screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
4223
4224         for (i = 0; i < screen->page->width; i += 8)
4225                 screen->tabs[i / 8] = 0x1;
4226
4227         term_page_set_scroll_region(screen->page_main, 0, screen->page->height);
4228         term_page_set_scroll_region(screen->page_alt, 0, screen->page->height);
4229 }
4230
4231 void term_screen_hard_reset(term_screen *screen) {
4232         assert(screen);
4233
4234         term_screen_soft_reset(screen);
4235         zero(screen->utf8);
4236         screen->state.cursor_x = 0;
4237         screen->state.cursor_y = 0;
4238         term_page_erase(screen->page_main, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false);
4239         term_page_erase(screen->page_alt, 0, 0, screen->page->width, screen->page->height, &screen->state.attr, screen->age, false);
4240 }
4241
4242 int term_screen_set_answerback(term_screen *screen, const char *answerback) {
4243         char *t = NULL;
4244
4245         assert_return(screen, -EINVAL);
4246
4247         if (answerback) {
4248                 t = strdup(answerback);
4249                 if (!t)
4250                         return -ENOMEM;
4251         }
4252
4253         free(screen->answerback);
4254         screen->answerback = t;
4255
4256         return 0;
4257 }
4258
4259 int term_screen_draw(term_screen *screen,
4260                      int (*draw_fn) (term_screen *screen,
4261                                      void *userdata,
4262                                      unsigned int x,
4263                                      unsigned int y,
4264                                      const term_attr *attr,
4265                                      const uint32_t *ch,
4266                                      size_t n_ch,
4267                                      unsigned int ch_width),
4268                      void *userdata,
4269                      uint64_t *fb_age) {
4270         uint64_t cell_age, line_age, age = 0;
4271         term_charbuf_t ch_buf;
4272         const uint32_t *ch_str;
4273         unsigned int i, j, cw;
4274         term_page *page;
4275         term_line *line;
4276         term_cell *cell;
4277         size_t ch_n;
4278         int r;
4279
4280         assert(screen);
4281         assert(draw_fn);
4282
4283         if (fb_age)
4284                 age = *fb_age;
4285
4286         page = screen->page;
4287
4288         for (j = 0; j < page->height; ++j) {
4289                 line = page->lines[j];
4290                 line_age = MAX(line->age, page->age);
4291
4292                 for (i = 0; i < page->width; ++i) {
4293                         term_attr attr;
4294
4295                         cell = &line->cells[i];
4296                         cell_age = MAX(cell->age, line_age);
4297
4298                         if (age != 0 && cell_age <= age)
4299                                 continue;
4300
4301                         ch_str = term_char_resolve(cell->ch, &ch_n, &ch_buf);
4302
4303                         /* Character-width of 0 is used for cleared cells.
4304                          * Always treat this as single-cell character, so
4305                          * renderers can assume ch_width is set properpy. */
4306                         cw = MAX(cell->cwidth, 1U);
4307
4308                         attr = cell->attr;
4309                         if (i == screen->state.cursor_x && j == screen->state.cursor_y &&
4310                             !(screen->flags & TERM_FLAG_HIDE_CURSOR))
4311                                 attr.inverse ^= 1;
4312
4313                         r = draw_fn(screen,
4314                                     userdata,
4315                                     i,
4316                                     j,
4317                                     &attr,
4318                                     ch_str,
4319                                     ch_n,
4320                                     cw);
4321                         if (r != 0)
4322                                 return r;
4323                 }
4324         }
4325
4326         if (fb_age)
4327                 *fb_age = screen->age;
4328
4329         return 0;
4330 }