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