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