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