chiark / gitweb /
terminal: provide display dimensions to API users
[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 "macro.h"
51 #include "term-internal.h"
52 #include "util.h"
53
54 int term_screen_new(term_screen **out, term_screen_write_fn write_fn, void *write_fn_data, term_screen_cmd_fn cmd_fn, void *cmd_fn_data) {
55         _cleanup_(term_screen_unrefp) term_screen *screen = NULL;
56         int r;
57
58         assert_return(out, -EINVAL);
59
60         screen = new0(term_screen, 1);
61         if (!screen)
62                 return -ENOMEM;
63
64         screen->ref = 1;
65         screen->age = 1;
66         screen->write_fn = write_fn;
67         screen->write_fn_data = write_fn_data;
68         screen->cmd_fn = cmd_fn;
69         screen->cmd_fn_data = cmd_fn_data;
70         screen->flags = TERM_FLAG_7BIT_MODE;
71         screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
72         screen->gl = &screen->g0;
73         screen->gr = &screen->g1;
74         screen->g0 = &term_unicode_lower;
75         screen->g1 = &term_unicode_upper;
76         screen->g2 = &term_unicode_lower;
77         screen->g3 = &term_unicode_upper;
78
79         screen->saved.cursor_x = 0;
80         screen->saved.cursor_y = 0;
81         screen->saved.attr = screen->attr;
82         screen->saved.gl = screen->gl;
83         screen->saved.gr = screen->gr;
84
85         r = term_page_new(&screen->page_main);
86         if (r < 0)
87                 return r;
88
89         r = term_page_new(&screen->page_alt);
90         if (r < 0)
91                 return r;
92
93         r = term_parser_new(&screen->parser, false);
94         if (r < 0)
95                 return r;
96
97         r = term_history_new(&screen->history_main);
98         if (r < 0)
99                 return r;
100
101         screen->page = screen->page_main;
102         screen->history = screen->history_main;
103
104         *out = screen;
105         screen = NULL;
106         return 0;
107 }
108
109 term_screen *term_screen_ref(term_screen *screen) {
110         if (!screen)
111                 return NULL;
112
113         assert_return(screen->ref > 0, NULL);
114
115         ++screen->ref;
116         return screen;
117 }
118
119 term_screen *term_screen_unref(term_screen *screen) {
120         if (!screen)
121                 return NULL;
122
123         assert_return(screen->ref > 0, NULL);
124
125         if (--screen->ref)
126                 return NULL;
127
128         free(screen->answerback);
129         free(screen->tabs);
130         term_history_free(screen->history_main);
131         term_page_free(screen->page_alt);
132         term_page_free(screen->page_main);
133         term_parser_free(screen->parser);
134         free(screen);
135
136         return NULL;
137 }
138
139 /*
140  * Write-Helpers
141  * Unfortunately, 7bit/8bit compat mode requires us to send C1 controls encoded
142  * as 7bit if asked by the application. This is really used in the wild, so we
143  * cannot fall back to "always 7bit".
144  * screen_write() is the underlying backend which forwards any writes to the
145  * users's callback. It's the users responsibility to buffer these and write
146  * them out once their call to term_screen_feed_*() returns.
147  * The SEQ_WRITE() and SEQ_WRITE_KEY() macros allow constructing C0/C1 sequences
148  * directly in the code-base without requiring any intermediate buffer during
149  * runtime.
150  */
151
152 #define C0_CSI "\e["
153 #define C1_CSI "\x9b"
154
155 #define SEQ(_screen, _prefix_esc, _c0, _c1, _seq) \
156                 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
157                         ((_prefix_esc) ? ("\e" _c0 _seq) : (_c0 _seq)) : \
158                         ((_prefix_esc) ? ("\e" _c1 _seq) : (_c1 _seq)))
159
160 #define SEQ_SIZE(_screen, _prefix_esc, _c0, _c1, _seq) \
161                 (((_screen)->flags & TERM_FLAG_7BIT_MODE) ? \
162                         ((_prefix_esc) ? sizeof("\e" _c0 _seq) : sizeof(_c0 _seq)) : \
163                         ((_prefix_esc) ? sizeof("\e" _c1 _seq) : sizeof(_c1 _seq)))
164
165 #define SEQ_WRITE_KEY(_screen, _prefix_esc, _c0, _c1, _seq) \
166                 screen_write((_screen), \
167                              SEQ((_screen), (_prefix_esc), \
168                                  _c0, _c1, _seq), \
169                              SEQ_SIZE((_screen), (_prefix_esc), \
170                                      _c0, _c1, _seq) - 1)
171
172 #define SEQ_WRITE(_screen, _c0, _c1, _seq) \
173                 SEQ_WRITE_KEY((_screen), false, _c0, _c1, _seq)
174
175 static int screen_write(term_screen *screen, const void *buf, size_t len) {
176         if (len < 1 || !screen->write_fn)
177                 return 0;
178
179         return screen->write_fn(screen, screen->write_fn_data, buf, len);
180 }
181
182 /*
183  * Command Forwarding
184  * Some commands cannot be handled by the screen-layer directly. Those are
185  * forwarded to the command-handler of the caller. This is rarely used and can
186  * safely be set to NULL.
187  */
188
189 static int screen_forward(term_screen *screen, unsigned int cmd, const term_seq *seq) {
190         if (!screen->cmd_fn)
191                 return 0;
192
193         return screen->cmd_fn(screen, screen->cmd_fn_data, cmd, seq);
194 }
195
196 /*
197  * Screen Helpers
198  * These helpers implement common-operations like cursor-handler and more, which
199  * are used by several command dispatchers.
200  */
201
202 static unsigned int screen_clamp_x(term_screen *screen, unsigned int x) {
203         if (x >= screen->page->width)
204                 return (screen->page->width > 0) ? screen->page->width - 1 : 0;
205
206         return x;
207 }
208
209 static unsigned int screen_clamp_y(term_screen *screen, unsigned int y) {
210         if (y >= screen->page->height)
211                 return (screen->page->height > 0) ? screen->page->height - 1 : 0;
212
213         return y;
214 }
215
216 static bool screen_tab_is_set(term_screen *screen, unsigned int pos) {
217         if (pos >= screen->page->width)
218                 return false;
219
220         return screen->tabs[pos / 8] & (1 << (pos % 8));
221 }
222
223 static inline void screen_age_cursor(term_screen *screen) {
224         term_cell *cell;
225
226         cell = term_page_get_cell(screen->page, screen->cursor_x, screen->cursor_y);
227         if (cell)
228                 cell->age = screen->age;
229 }
230
231 static void screen_cursor_clear_wrap(term_screen *screen) {
232         screen->flags &= ~TERM_FLAG_PENDING_WRAP;
233 }
234
235 static void screen_cursor_set(term_screen *screen, unsigned int x, unsigned int y) {
236         x = screen_clamp_x(screen, x);
237         y = screen_clamp_y(screen, y);
238
239         if (x == screen->cursor_x && y == screen->cursor_y)
240                 return;
241
242         if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
243                 screen_age_cursor(screen);
244
245         screen->cursor_x = x;
246         screen->cursor_y = y;
247
248         if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
249                 screen_age_cursor(screen);
250 }
251
252 static void screen_cursor_set_rel(term_screen *screen, unsigned int x, unsigned int y) {
253         if (screen->flags & TERM_FLAG_ORIGIN_MODE) {
254                 x = screen_clamp_x(screen, x);
255                 y = screen_clamp_x(screen, y) + screen->page->scroll_idx;
256
257                 if (y >= screen->page->scroll_idx + screen->page->scroll_num) {
258                         y = screen->page->scroll_idx + screen->page->scroll_num;
259                         if (screen->page->scroll_num > 0)
260                                 y -= 1;
261                 }
262         }
263
264         screen_cursor_set(screen, x, y);
265 }
266
267 static void screen_cursor_left(term_screen *screen, unsigned int num) {
268         if (num > screen->cursor_x)
269                 num = screen->cursor_x;
270
271         screen_cursor_set(screen, screen->cursor_x - num, screen->cursor_y);
272 }
273
274 static void screen_cursor_left_tab(term_screen *screen, unsigned int num) {
275         unsigned int i;
276
277         i = screen->cursor_x;
278         while (i > 0 && num > 0) {
279                 if (screen_tab_is_set(screen, --i))
280                         --num;
281         }
282
283         screen_cursor_set(screen, i, screen->cursor_y);
284 }
285
286 static void screen_cursor_right(term_screen *screen, unsigned int num) {
287         if (num > screen->page->width)
288                 num = screen->page->width;
289
290         screen_cursor_set(screen, screen->cursor_x + num, screen->cursor_y);
291 }
292
293 static void screen_cursor_right_tab(term_screen *screen, unsigned int num) {
294         unsigned int i;
295
296         i = screen->cursor_x;
297         while (i + 1 < screen->page->width && num > 0) {
298                 if (screen_tab_is_set(screen, ++i))
299                         --num;
300         }
301
302         screen_cursor_set(screen, i, screen->cursor_y);
303 }
304
305 static void screen_cursor_up(term_screen *screen, unsigned int num, bool scroll) {
306         unsigned int max;
307
308         if (screen->cursor_y < screen->page->scroll_idx) {
309                 if (num > screen->cursor_y)
310                         num = screen->cursor_y;
311
312                 screen_cursor_set(screen, screen->cursor_x, screen->cursor_y - num);
313         } else {
314                 max = screen->cursor_y - screen->page->scroll_idx;
315                 if (num > max) {
316                         if (num < 1)
317                                 return;
318
319                         if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
320                                 screen_age_cursor(screen);
321
322                         if (scroll)
323                                 term_page_scroll_down(screen->page, num - max, &screen->attr, screen->age, NULL);
324
325                         screen->cursor_y = screen->page->scroll_idx;
326
327                         if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
328                                 screen_age_cursor(screen);
329                 } else {
330                         screen_cursor_set(screen, screen->cursor_x, screen->cursor_y - num);
331                 }
332         }
333 }
334
335 static void screen_cursor_down(term_screen *screen, unsigned int num, bool scroll) {
336         unsigned int max;
337
338         if (screen->cursor_y >= screen->page->scroll_idx + screen->page->scroll_num) {
339                 if (num > screen->page->height)
340                         num = screen->page->height;
341
342                 screen_cursor_set(screen, screen->cursor_x, screen->cursor_y - num);
343         } else {
344                 max = screen->page->scroll_idx + screen->page->scroll_num - 1 - screen->cursor_y;
345                 if (num > max) {
346                         if (num < 1)
347                                 return;
348
349                         if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
350                                 screen_age_cursor(screen);
351
352                         if (scroll)
353                                 term_page_scroll_up(screen->page, num - max, &screen->attr, screen->age, screen->history);
354
355                         screen->cursor_y = screen->page->scroll_idx + screen->page->scroll_num - 1;
356
357                         if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
358                                 screen_age_cursor(screen);
359                 } else {
360                         screen_cursor_set(screen, screen->cursor_x, screen->cursor_y + num);
361                 }
362         }
363 }
364
365 static inline void set_reset(term_screen *screen, unsigned int flag, bool set) {
366         if (set)
367                 screen->flags |= flag;
368         else
369                 screen->flags &= ~flag;
370 }
371
372 static void screen_mode_change(term_screen *screen, unsigned int mode, bool dec, bool set) {
373         switch (mode) {
374         case 1:
375                 if (dec) {
376                         /*
377                          * DECCKM: cursor-keys
378                          * TODO
379                          */
380                         set_reset(screen, TERM_FLAG_CURSOR_KEYS, set);
381                 }
382
383                 break;
384         case 6:
385                 if (dec) {
386                         /*
387                          * DECOM: origin-mode
388                          * TODO
389                          */
390                         set_reset(screen, TERM_FLAG_ORIGIN_MODE, set);
391                 }
392
393                 break;
394         case 7:
395                 if (dec) {
396                         /*
397                          * DECAWN: auto-wrap mode
398                          * TODO
399                          */
400                         set_reset(screen, TERM_FLAG_AUTO_WRAP, set);
401                 }
402
403                 break;
404         case 20:
405                 if (!dec) {
406                         /*
407                          * LNM: line-feed/new-line mode
408                          * TODO
409                          */
410                         set_reset(screen, TERM_FLAG_NEWLINE_MODE, set);
411                 }
412
413                 break;
414         case 25:
415                 if (dec) {
416                         /*
417                          * DECTCEM: text-cursor-enable
418                          * TODO
419                          */
420                         set_reset(screen, TERM_FLAG_HIDE_CURSOR, !set);
421                 }
422
423                 break;
424         }
425 }
426
427 /* map a character according to current GL and GR maps */
428 static uint32_t screen_map(term_screen *screen, uint32_t val) {
429         uint32_t nval = -1U;
430
431         /* 32 and 127 always map to identity. 160 and 255 map to identity iff a
432          * 96 character set is loaded into GR. Values above 255 always map to
433          * identity. */
434         switch (val) {
435         case 33 ... 126:
436                 if (screen->glt) {
437                         nval = (**screen->glt)[val - 32];
438                         screen->glt = NULL;
439                 } else {
440                         nval = (**screen->gl)[val - 32];
441                 }
442                 break;
443         case 160 ... 255:
444                 if (screen->grt) {
445                         nval = (**screen->grt)[val - 160];
446                         screen->grt = NULL;
447                 } else {
448                         nval = (**screen->gr)[val - 160];
449                 }
450                 break;
451         }
452
453         return (nval == -1U) ? val : nval;
454 }
455
456 /*
457  * Command Handlers
458  * This is the unofficial documentation of all the TERM_CMD_* definitions. Each
459  * handled command has a separate function with an extensive comment on the
460  * semantics of the command.
461  * Note that many semantics are unknown and need to be verified. This is mostly
462  * about error-handling, though. Applications rarely rely on those features.
463  */
464
465 static int screen_DA1(term_screen *screen, const term_seq *seq);
466 static int screen_LF(term_screen *screen, const term_seq *seq);
467
468 static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) {
469         term_char_t ch = TERM_CHAR_NULL;
470         uint32_t c;
471
472         if (screen->cursor_x + 1 == screen->page->width
473             && screen->flags & TERM_FLAG_PENDING_WRAP
474             && screen->flags & TERM_FLAG_AUTO_WRAP) {
475                 screen_cursor_down(screen, 1, true);
476                 screen_cursor_set(screen, 0, screen->cursor_y);
477         }
478
479         screen_cursor_clear_wrap(screen);
480
481         c = screen_map(screen, seq->terminator);
482         ch = term_char_merge(ch, screen_map(screen, c));
483         term_page_write(screen->page, screen->cursor_x, screen->cursor_y, ch, 1, &screen->attr, screen->age, false);
484
485         if (screen->cursor_x + 1 == screen->page->width)
486                 screen->flags |= TERM_FLAG_PENDING_WRAP;
487         else
488                 screen_cursor_right(screen, 1);
489
490         return 0;
491 }
492
493 static int screen_BEL(term_screen *screen, const term_seq *seq) {
494         /*
495          * BEL - sound bell tone
496          * This command should trigger an acoustic bell. Usually, this is
497          * forwarded directly to the pcspkr. However, bells have become quite
498          * uncommon and annoying, so we're not implementing them here. Instead,
499          * it's one of the commands we forward to the caller.
500          */
501
502         return screen_forward(screen, TERM_CMD_BEL, seq);
503 }
504
505 static int screen_BS(term_screen *screen, const term_seq *seq) {
506         /*
507          * BS - backspace
508          * Move cursor one cell to the left. If already at the left margin,
509          * nothing happens.
510          */
511
512         screen_cursor_clear_wrap(screen);
513         screen_cursor_left(screen, 1);
514         return 0;
515 }
516
517 static int screen_CBT(term_screen *screen, const term_seq *seq) {
518         /*
519          * CBT - cursor-backward-tabulation
520          * Move the cursor @args[0] tabs backwards (to the left). The
521          * current cursor cell, in case it's a tab, is not counted.
522          * Furthermore, the cursor cannot be moved beyond position 0 and
523          * it will stop there.
524          *
525          * Defaults:
526          *   args[0]: 1
527          */
528
529         unsigned int num = 1;
530
531         if (seq->args[0] > 0)
532                 num = seq->args[0];
533
534         screen_cursor_clear_wrap(screen);
535         screen_cursor_left_tab(screen, num);
536
537         return 0;
538 }
539
540 static int screen_CHA(term_screen *screen, const term_seq *seq) {
541         /*
542          * CHA - cursor-horizontal-absolute
543          * Move the cursor to position @args[0] in the current line. The
544          * cursor cannot be moved beyond the rightmost cell and will stop
545          * there.
546          *
547          * Defaults:
548          *   args[0]: 1
549          */
550
551         unsigned int pos = 1;
552
553         if (seq->args[0] > 0)
554                 pos = seq->args[0];
555
556         screen_cursor_clear_wrap(screen);
557         screen_cursor_set(screen, pos - 1, screen->cursor_y);
558
559         return 0;
560 }
561
562 static int screen_CHT(term_screen *screen, const term_seq *seq) {
563         /*
564          * CHT - cursor-horizontal-forward-tabulation
565          * Move the cursor @args[0] tabs forward (to the right). The
566          * current cursor cell, in case it's a tab, is not counted.
567          * Furthermore, the cursor cannot be moved beyond the rightmost cell
568          * and will stop there.
569          *
570          * Defaults:
571          *   args[0]: 1
572          */
573
574         unsigned int num = 1;
575
576         if (seq->args[0] > 0)
577                 num = seq->args[0];
578
579         screen_cursor_clear_wrap(screen);
580         screen_cursor_right_tab(screen, num);
581
582         return 0;
583 }
584
585 static int screen_CNL(term_screen *screen, const term_seq *seq) {
586         /*
587          * CNL - cursor-next-line
588          * Move the cursor @args[0] lines down.
589          *
590          * TODO: Does this stop at the bottom or cause a scroll-up?
591          *
592          * Defaults:
593          *   args[0]: 1
594          */
595
596         unsigned int num = 1;
597
598         if (seq->args[0] > 0)
599                 num = seq->args[0];
600
601         screen_cursor_clear_wrap(screen);
602         screen_cursor_down(screen, num, false);
603
604         return 0;
605 }
606
607 static int screen_CPL(term_screen *screen, const term_seq *seq) {
608         /*
609          * CPL - cursor-preceding-line
610          * Move the cursor @args[0] lines up.
611          *
612          * TODO: Does this stop at the top or cause a scroll-up?
613          *
614          * Defaults:
615          *   args[0]: 1
616          */
617
618         unsigned int num = 1;
619
620         if (seq->args[0] > 0)
621                 num = seq->args[0];
622
623         screen_cursor_clear_wrap(screen);
624         screen_cursor_up(screen, num, false);
625
626         return 0;
627 }
628
629 static int screen_CR(term_screen *screen, const term_seq *seq) {
630         /*
631          * CR - carriage-return
632          * Move the cursor to the left margin on the current line.
633          */
634
635         screen_cursor_clear_wrap(screen);
636         screen_cursor_set(screen, 0, screen->cursor_y);
637
638         return 0;
639 }
640
641 static int screen_CUB(term_screen *screen, const term_seq *seq) {
642         /*
643          * CUB - cursor-backward
644          * Move the cursor @args[0] positions to the left. The cursor stops
645          * at the left-most position.
646          *
647          * Defaults:
648          *   args[0]: 1
649          */
650
651         unsigned int num = 1;
652
653         if (seq->args[0] > 0)
654                 num = seq->args[0];
655
656         screen_cursor_clear_wrap(screen);
657         screen_cursor_left(screen, num);
658
659         return 0;
660 }
661
662 static int screen_CUD(term_screen *screen, const term_seq *seq) {
663         /*
664          * CUD - cursor-down
665          * Move the cursor @args[0] positions down. The cursor stops at the
666          * bottom margin. If it was already moved further, it stops at the
667          * bottom line.
668          *
669          * Defaults:
670          *   args[0]: 1
671          */
672
673         unsigned int num = 1;
674
675         if (seq->args[0] > 0)
676                 num = seq->args[0];
677
678         screen_cursor_clear_wrap(screen);
679         screen_cursor_down(screen, num, false);
680
681         return 0;
682 }
683
684 static int screen_CUF(term_screen *screen, const term_seq *seq) {
685         /*
686          * CUF -cursor-forward
687          * Move the cursor @args[0] positions to the right. The cursor stops
688          * at the right-most position.
689          *
690          * Defaults:
691          *   args[0]: 1
692          */
693
694         unsigned int num = 1;
695
696         if (seq->args[0] > 0)
697                 num = seq->args[0];
698
699         screen_cursor_clear_wrap(screen);
700         screen_cursor_right(screen, num);
701
702         return 0;
703 }
704
705 static int screen_CUP(term_screen *screen, const term_seq *seq) {
706         /*
707          * CUP - cursor-position
708          * Moves the cursor to position @args[1] x @args[0]. If either is 0, it
709          * is treated as 1. The positions are subject to the origin-mode and
710          * clamped to the addressable with/height.
711          *
712          * Defaults:
713          *   args[0]: 1
714          *   args[1]: 1
715          */
716
717         unsigned int x = 1, y = 1;
718
719         if (seq->args[0] > 0)
720                 y = seq->args[0];
721         if (seq->args[1] > 0)
722                 x = seq->args[1];
723
724         screen_cursor_clear_wrap(screen);
725         screen_cursor_set_rel(screen, x - 1, y - 1);
726
727         return 0;
728 }
729
730 static int screen_CUU(term_screen *screen, const term_seq *seq) {
731         /*
732          * CUU - cursor-up
733          * Move the cursor @args[0] positions up. The cursor stops at the
734          * top margin. If it was already moved further, it stops at the
735          * top line.
736          *
737          * Defaults:
738          *   args[0]: 1
739          *
740          */
741
742         unsigned int num = 1;
743
744         if (seq->args[0] > 0)
745                 num = seq->args[0];
746
747         screen_cursor_clear_wrap(screen);
748         screen_cursor_up(screen, num, false);
749
750         return 0;
751 }
752
753 static int screen_DA1(term_screen *screen, const term_seq *seq) {
754         /*
755          * DA1 - primary-device-attributes
756          * The primary DA asks for basic terminal features. We simply return
757          * a hard-coded list of features we implement.
758          * Note that the primary DA asks for supported features, not currently
759          * enabled features.
760          *
761          * The terminal's answer is:
762          *   ^[ ? 64 ; ARGS c
763          * The first argument, 64, is fixed and denotes a VT420, the last
764          * DEC-term that extended this number.
765          * All following arguments denote supported features. Note
766          * that at most 15 features can be sent (max CSI args). It is safe to
767          * send more, but clients might not be able to parse them. This is a
768          * client's problem and we shouldn't care. There is no other way to
769          * send those feature lists, so we have to extend them beyond 15 in
770          * those cases.
771          *
772          * Known modes:
773          *    1: 132 column mode
774          *       The 132 column mode is supported by the terminal.
775          *    2: printer port
776          *       A priner-port is supported and can be addressed via
777          *       control-codes.
778          *    3: ReGIS graphics
779          *       Support for ReGIS graphics is available. The ReGIS routines
780          *       provide the "remote graphics instruction set" and allow basic
781          *       vector-rendering.
782          *    4: sixel
783          *       Support of Sixel graphics is available. This provides access
784          *       to the sixel bitmap routines.
785          *    6: selective erase
786          *       The terminal supports DECSCA and related selective-erase
787          *       functions. This allows to protect specific cells from being
788          *       erased, if specified.
789          *    7: soft character set (DRCS)
790          *       TODO: ?
791          *    8: user-defined keys (UDKs)
792          *       TODO: ?
793          *    9: national-replacement character sets (NRCS)
794          *       National-replacement character-sets are available.
795          *   12: Yugoslavian (SCS)
796          *       TODO: ?
797          *   15: technical character set
798          *       The DEC technical-character-set is available.
799          *   18: windowing capability
800          *       TODO: ?
801          *   21: horizontal scrolling
802          *       TODO: ?
803          *   22: ANSII color
804          *       TODO: ?
805          *   23: Greek
806          *       TODO: ?
807          *   24: Turkish
808          *       TODO: ?
809          *   29: ANSI text locator
810          *       TODO: ?
811          *   42: ISO Latin-2 character set
812          *       TODO: ?
813          *   44: PCTerm
814          *       TODO: ?
815          *   45: soft keymap
816          *       TODO: ?
817          *   46: ASCII emulation
818          *       TODO: ?
819          */
820
821         return SEQ_WRITE(screen, C0_CSI, C1_CSI, "?64;1;6;9;15c");
822 }
823
824 static int screen_DA2(term_screen *screen, const term_seq *seq) {
825         /*
826          * DA2 - secondary-device-attributes
827          * The secondary DA asks for the terminal-ID, firmware versions and
828          * other non-primary attributes. All these values are
829          * informational-only and should not be used by the host to detect
830          * terminal features.
831          *
832          * The terminal's response is:
833          *   ^[ > 61 ; FIRMWARE ; KEYBOARD c
834          * whereas 65 is fixed for VT525 terminals, the last terminal-line that
835          * increased this number. FIRMWARE is the firmware
836          * version encoded as major/minor (20 == 2.0) and KEYBOARD is 0 for STD
837          * keyboard and 1 for PC keyboards.
838          *
839          * We replace the firmware-version with the systemd-version so clients
840          * can decode it again.
841          */
842
843         return SEQ_WRITE(screen, C0_CSI, C1_CSI, ">65;" PACKAGE_VERSION ";1c");
844 }
845
846 static int screen_DA3(term_screen *screen, const term_seq *seq) {
847         /*
848          * DA3 - tertiary-device-attributes
849          * The tertiary DA is used to query the terminal-ID.
850          *
851          * The terminal's response is:
852          *   ^P ! | XX AA BB CC ^\
853          * whereas all four parameters are hexadecimal-encoded pairs. XX
854          * denotes the manufacturing site, AA BB CC is the terminal's ID.
855          */
856
857         /* we do not support tertiary DAs */
858         return 0;
859 }
860
861 static int screen_DC1(term_screen *screen, const term_seq *seq) {
862         /*
863          * DC1 - device-control-1 or XON
864          * This clears any previous XOFF and resumes terminal-transmission.
865          */
866
867         /* we do not support XON */
868         return 0;
869 }
870
871 static int screen_DC3(term_screen *screen, const term_seq *seq) {
872         /*
873          * DC3 - device-control-3 or XOFF
874          * Stops terminal transmission. No further characters are sent until
875          * an XON is received.
876          */
877
878         /* we do not support XOFF */
879         return 0;
880 }
881
882 static int screen_DCH(term_screen *screen, const term_seq *seq) {
883         /*
884          * DCH - delete-character
885          * This deletes @argv[0] characters at the current cursor position. As
886          * characters are deleted, the remaining characters between the cursor
887          * and right margin move to the left. Character attributes move with the
888          * characters. The terminal adds blank spaces with no visual character
889          * attributes at the right margin. DCH has no effect outside the
890          * scrolling margins.
891          *
892          * Defaults:
893          *   args[0]: 1
894          */
895
896         unsigned int num = 1;
897
898         if (seq->args[0] > 0)
899                 num = seq->args[0];
900
901         screen_cursor_clear_wrap(screen);
902         term_page_delete_cells(screen->page, screen->cursor_x, screen->cursor_y, num, &screen->attr, screen->age);
903
904         return 0;
905 }
906
907 static int screen_DECALN(term_screen *screen, const term_seq *seq) {
908         /*
909          * DECALN - screen-alignment-pattern
910          *
911          * Probably not worth implementing.
912          */
913
914         return 0;
915 }
916
917 static int screen_DECANM(term_screen *screen, const term_seq *seq) {
918         /*
919          * DECANM - ansi-mode
920          * Set the terminal into VT52 compatibility mode. Control sequences
921          * overlap with regular sequences so we have to detect them early before
922          * dispatching them.
923          *
924          * Probably not worth implementing.
925          */
926
927         return 0;
928 }
929
930 static int screen_DECBI(term_screen *screen, const term_seq *seq) {
931         /*
932          * DECBI - back-index
933          * This control function moves the cursor backward one column. If the
934          * cursor is at the left margin, then all screen data within the margin
935          * moves one column to the right. The column that shifted past the right
936          * margin is lost.
937          * DECBI adds a new column at the left margin with no visual attributes.
938          * DECBI does not affect the margins. If the cursor is beyond the
939          * left-margin at the left border, then the terminal ignores DECBI.
940          *
941          * Probably not worth implementing.
942          */
943
944         return 0;
945 }
946
947 static int screen_DECCARA(term_screen *screen, const term_seq *seq) {
948         /*
949          * DECCARA - change-attributes-in-rectangular-area
950          *
951          * Probably not worth implementing.
952          */
953
954         return 0;
955 }
956
957 static int screen_DECCRA(term_screen *screen, const term_seq *seq) {
958         /*
959          * DECCRA - copy-rectangular-area
960          *
961          * Probably not worth implementing.
962          */
963
964         return 0;
965 }
966
967 static int screen_DECDC(term_screen *screen, const term_seq *seq) {
968         /*
969          * DECDC - delete-column
970          *
971          * Probably not worth implementing.
972          */
973
974         return 0;
975 }
976
977 static int screen_DECDHL_BH(term_screen *screen, const term_seq *seq) {
978         /*
979          * DECDHL_BH - double-width-double-height-line: bottom half
980          *
981          * Probably not worth implementing.
982          */
983
984         return 0;
985 }
986
987 static int screen_DECDHL_TH(term_screen *screen, const term_seq *seq) {
988         /*
989          * DECDHL_TH - double-width-double-height-line: top half
990          *
991          * Probably not worth implementing.
992          */
993
994         return 0;
995 }
996
997 static int screen_DECDWL(term_screen *screen, const term_seq *seq) {
998         /*
999          * DECDWL - double-width-single-height-line
1000          *
1001          * Probably not worth implementing.
1002          */
1003
1004         return 0;
1005 }
1006
1007 static int screen_DECEFR(term_screen *screen, const term_seq *seq) {
1008         /*
1009          * DECEFR - enable-filter-rectangle
1010          * Defines the coordinates of a filter rectangle (top, left, bottom,
1011          * right as @args[0] to @args[3]) and activates it.
1012          * Anytime the locator is detected outside of the filter rectangle, an
1013          * outside rectangle event is generated and the rectangle is disabled.
1014          * Filter rectangles are always treated as "one-shot" events. Any
1015          * parameters that are omitted default to the current locator position.
1016          * If all parameters are omitted, any locator motion will be reported.
1017          * DECELR always cancels any prevous rectangle definition.
1018          *
1019          * The locator is usually associated with the mouse-cursor, but based
1020          * on cells instead of pixels. See DECELR how to initialize and enable
1021          * it. DECELR can also enable pixel-mode instead of cell-mode.
1022          *
1023          * TODO: implement
1024          */
1025
1026         return 0;
1027 }
1028
1029 static int screen_DECELF(term_screen *screen, const term_seq *seq) {
1030         /*
1031          * DECELF - enable-local-functions
1032          *
1033          * Probably not worth implementing.
1034          */
1035
1036         return 0;
1037 }
1038
1039 static int screen_DECELR(term_screen *screen, const term_seq *seq) {
1040         /*
1041          * DECELR - enable-locator-reporting
1042          * This changes the locator-reporting mode. @args[0] specifies the mode
1043          * to set, 0 disables locator-reporting, 1 enables it continuously, 2
1044          * enables it for a single report. @args[1] specifies the
1045          * precision-mode. 0 and 2 set the reporting to cell-precision, 1 sets
1046          * pixel-precision.
1047          *
1048          * Defaults:
1049          *   args[0]: 0
1050          *   args[1]: 0
1051          *
1052          * TODO: implement
1053          */
1054
1055         return 0;
1056 }
1057
1058 static int screen_DECERA(term_screen *screen, const term_seq *seq) {
1059         /*
1060          * DECERA - erase-rectangular-area
1061          *
1062          * Probably not worth implementing.
1063          */
1064
1065         return 0;
1066 }
1067
1068 static int screen_DECFI(term_screen *screen, const term_seq *seq) {
1069         /*
1070          * DECFI - forward-index
1071          * This control function moves the cursor forward one column. If the
1072          * cursor is at the right margin, then all screen data within the
1073          * margins moves one column to the left. The column shifted past the
1074          * left margin is lost.
1075          * DECFI adds a new column at the right margin, with no visual
1076          * attributes. DECFI does not affect margins. If the cursor is beyond
1077          * the right margin at the border of the page when the terminal
1078          * receives DECFI, then the terminal ignores DECFI.
1079          *
1080          * Probably not worth implementing.
1081          */
1082
1083         return 0;
1084 }
1085
1086 static int screen_DECFRA(term_screen *screen, const term_seq *seq) {
1087         /*
1088          * DECFRA - fill-rectangular-area
1089          *
1090          * Probably not worth implementing.
1091          */
1092
1093         return 0;
1094 }
1095
1096 static int screen_DECIC(term_screen *screen, const term_seq *seq) {
1097         /*
1098          * DECIC - insert-column
1099          *
1100          * Probably not worth implementing.
1101          */
1102
1103         return 0;
1104 }
1105
1106 static int screen_DECID(term_screen *screen, const term_seq *seq) {
1107         /*
1108          * DECID - return-terminal-id
1109          * This is an obsolete form of TERM_CMD_DA1.
1110          */
1111
1112         return screen_DA1(screen, seq);
1113 }
1114
1115 static int screen_DECINVM(term_screen *screen, const term_seq *seq) {
1116         /*
1117          * DECINVM - invoke-macro
1118          *
1119          * Probably not worth implementing.
1120          */
1121
1122         return 0;
1123 }
1124
1125 static int screen_DECKBD(term_screen *screen, const term_seq *seq) {
1126         /*
1127          * DECKBD - keyboard-language-selection
1128          *
1129          * Probably not worth implementing.
1130          */
1131
1132         return 0;
1133 }
1134
1135 static int screen_DECKPAM(term_screen *screen, const term_seq *seq) {
1136         /*
1137          * DECKPAM - keypad-application-mode
1138          * Enables the keypad-application mode. If enabled, the keypad sends
1139          * special characters instead of the printed characters. This way,
1140          * applications can detect whether a numeric key was pressed on the
1141          * top-row or on the keypad.
1142          * Default is keypad-numeric-mode.
1143          */
1144
1145         screen->flags |= TERM_FLAG_KEYPAD_MODE;
1146
1147         return 0;
1148 }
1149
1150 static int screen_DECKPNM(term_screen *screen, const term_seq *seq) {
1151         /*
1152          * DECKPNM - keypad-numeric-mode
1153          * This disables the keypad-application-mode (DECKPAM) and returns to
1154          * the keypad-numeric-mode. Keypresses on the keypad generate the same
1155          * sequences as corresponding keypresses on the main keyboard.
1156          * Default is keypad-numeric-mode.
1157          */
1158
1159         screen->flags &= ~TERM_FLAG_KEYPAD_MODE;
1160
1161         return 0;
1162 }
1163
1164 static int screen_DECLFKC(term_screen *screen, const term_seq *seq) {
1165         /*
1166          * DECLFKC - local-function-key-control
1167          *
1168          * Probably not worth implementing.
1169          */
1170
1171         return 0;
1172 }
1173
1174 static int screen_DECLL(term_screen *screen, const term_seq *seq) {
1175         /*
1176          * DECLL - load-leds
1177          *
1178          * Probably not worth implementing.
1179          */
1180
1181         return 0;
1182 }
1183
1184 static int screen_DECLTOD(term_screen *screen, const term_seq *seq) {
1185         /*
1186          * DECLTOD - load-time-of-day
1187          *
1188          * Probably not worth implementing.
1189          */
1190
1191         return 0;
1192 }
1193
1194 static int screen_DECPCTERM(term_screen *screen, const term_seq *seq) {
1195         /*
1196          * DECPCTERM - pcterm-mode
1197          * This enters/exits the PCTerm mode. Default mode is VT-mode. It can
1198          * also select parameters for scancode/keycode mappings in SCO mode.
1199          *
1200          * Definitely not worth implementing. Lets kill PCTerm/SCO modes!
1201          */
1202
1203         return 0;
1204 }
1205
1206 static int screen_DECPKA(term_screen *screen, const term_seq *seq) {
1207         /*
1208          * DECPKA - program-key-action
1209          *
1210          * Probably not worth implementing.
1211          */
1212
1213         return 0;
1214 }
1215
1216 static int screen_DECPKFMR(term_screen *screen, const term_seq *seq) {
1217         /*
1218          * DECPKFMR - program-key-free-memory-report
1219          *
1220          * Probably not worth implementing.
1221          */
1222
1223         return 0;
1224 }
1225
1226 static int screen_DECRARA(term_screen *screen, const term_seq *seq) {
1227         /*
1228          * DECRARA - reverse-attributes-in-rectangular-area
1229          *
1230          * Probably not worth implementing.
1231          */
1232
1233         return 0;
1234 }
1235
1236 static int screen_DECRC(term_screen *screen, const term_seq *seq) {
1237         /*
1238          * DECRC - restore-cursor
1239          * Restores the terminal to the state saved by the save cursor (DECSC)
1240          * function. This includes more than just the cursor-position.
1241          *
1242          * If nothing was saved by DECSC, then DECRC performs the following
1243          * actions:
1244          *   * Moves the cursor to the home position (upper left of screen).
1245          *   * Resets origin mode (DECOM).
1246          *   * Turns all character attributes off (normal setting).
1247          *   * Maps the ASCII character set into GL, and the DEC Supplemental
1248          *     Graphic set into GR.
1249          *
1250          * The terminal maintains a separate DECSC buffer for the main display
1251          * and the status line. This feature lets you save a separate operating
1252          * state for the main display and the status line.
1253          */
1254
1255         screen->attr = screen->saved.attr;
1256         screen->gl = screen->saved.gl;
1257         screen->gr = screen->saved.gr;
1258         screen->glt = screen->saved.glt;
1259         screen->grt = screen->saved.grt;
1260         set_reset(screen, TERM_FLAG_AUTO_WRAP, screen->flags & TERM_FLAG_AUTO_WRAP);
1261         set_reset(screen, TERM_FLAG_ORIGIN_MODE, screen->flags & TERM_FLAG_ORIGIN_MODE);
1262         screen_cursor_set(screen, screen->saved.cursor_x, screen->saved.cursor_y);
1263
1264         return 0;
1265 }
1266
1267 static int screen_DECREQTPARM(term_screen *screen, const term_seq *seq) {
1268         /*
1269          * DECREQTPARM - request-terminal-parameters
1270          * The sequence DECREPTPARM is sent by the terminal controller to notify
1271          * the host of the status of selected terminal parameters. The status
1272          * sequence may be sent when requested by the host or at the terminal's
1273          * discretion. DECREPTPARM is sent upon receipt of a DECREQTPARM.
1274          *
1275          * If @args[0] is 0, this marks a request and the terminal is allowed
1276          * to send DECREPTPARM messages without request. If it is 1, the same
1277          * applies but the terminal should no longer send DECREPTPARM
1278          * unrequested.
1279          * 2 and 3 mark a report, but 3 is only used if the terminal answers as
1280          * an explicit request with @args[0] == 1.
1281          *
1282          * The other arguments are ignored in requests, but have the following
1283          * meaning in responses:
1284          *   args[1]: 1=no-parity-set 4=parity-set-and-odd 5=parity-set-and-even
1285          *   args[2]: 1=8bits-per-char 2=7bits-per-char
1286          *   args[3]: transmission-speed
1287          *   args[4]: receive-speed
1288          *   args[5]: 1=bit-rate-multiplier-is-16
1289          *   args[6]: This value communicates the four switch values in block 5
1290          *            of SETUP B, which are only visible to the user when an STP
1291          *            option is installed. These bits may be assigned for an STP
1292          *            device. The four bits are a decimal-encoded binary number.
1293          *            Value between 0-15.
1294          *
1295          * The transmission/receive speeds have mappings for number => bits/s
1296          * which are quite weird. Examples are: 96->3600, 112->9600, 120->19200
1297          *
1298          * Defaults:
1299          *   args[0]: 0
1300          */
1301
1302         if (seq->n_args < 1 || seq->args[0] == 0) {
1303                 screen->flags &= ~TERM_FLAG_INHIBIT_TPARM;
1304                 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "2;1;1;120;120;1;0x");
1305         } else if (seq->args[0] == 1) {
1306                 screen->flags |= TERM_FLAG_INHIBIT_TPARM;
1307                 return SEQ_WRITE(screen, C0_CSI, C1_CSI, "3;1;1;120;120;1;0x");
1308         } else {
1309                 return 0;
1310         }
1311 }
1312
1313 static int screen_DECRPKT(term_screen *screen, const term_seq *seq) {
1314         /*
1315          * DECRPKT - report-key-type
1316          * Response to DECRQKT, we can safely ignore it as we're the one sending
1317          * it to the host.
1318          */
1319
1320         return 0;
1321 }
1322
1323 static int screen_DECRQCRA(term_screen *screen, const term_seq *seq) {
1324         /*
1325          * DECRQCRA - request-checksum-of-rectangular-area
1326          *
1327          * Probably not worth implementing.
1328          */
1329
1330         return 0;
1331 }
1332
1333 static int screen_DECRQDE(term_screen *screen, const term_seq *seq) {
1334         /*
1335          * DECRQDE - request-display-extent
1336          *
1337          * Probably not worth implementing.
1338          */
1339
1340         return 0;
1341 }
1342
1343 static int screen_DECRQKT(term_screen *screen, const term_seq *seq) {
1344         /*
1345          * DECRQKT - request-key-type
1346          *
1347          * Probably not worth implementing.
1348          */
1349
1350         return 0;
1351 }
1352
1353 static int screen_DECRQLP(term_screen *screen, const term_seq *seq) {
1354         /*
1355          * DECRQLP - request-locator-position
1356          * See DECELR for locator-information.
1357          *
1358          * TODO: document and implement
1359          */
1360
1361         return 0;
1362 }
1363
1364 static int screen_DECRQM_ANSI(term_screen *screen, const term_seq *seq) {
1365         /*
1366          * DECRQM_ANSI - request-mode-ansi
1367          * The host sends this control function to find out if a particular mode
1368          * is set or reset. The terminal responds with a report mode function.
1369          * @args[0] contains the mode to query.
1370          *
1371          * Response is DECRPM with the first argument set to the mode that was
1372          * queried, second argument is 0 if mode is invalid, 1 if mode is set,
1373          * 2 if mode is not set (reset), 3 if mode is permanently set and 4 if
1374          * mode is permanently not set (reset):
1375          *   ANSI: ^[ MODE ; VALUE $ y
1376          *   DEC:  ^[ ? MODE ; VALUE $ y
1377          *
1378          * TODO: implement
1379          */
1380
1381         return 0;
1382 }
1383
1384 static int screen_DECRQM_DEC(term_screen *screen, const term_seq *seq) {
1385         /*
1386          * DECRQM_DEC - request-mode-dec
1387          * Same as DECRQM_ANSI but for DEC modes.
1388          *
1389          * TODO: implement
1390          */
1391
1392         return 0;
1393 }
1394
1395 static int screen_DECRQPKFM(term_screen *screen, const term_seq *seq) {
1396         /*
1397          * DECRQPKFM - request-program-key-free-memory
1398          *
1399          * Probably not worth implementing.
1400          */
1401
1402         return 0;
1403 }
1404
1405 static int screen_DECRQPSR(term_screen *screen, const term_seq *seq) {
1406         /*
1407          * DECRQPSR - request-presentation-state-report
1408          *
1409          * Probably not worth implementing.
1410          */
1411
1412         return 0;
1413 }
1414
1415 static int screen_DECRQTSR(term_screen *screen, const term_seq *seq) {
1416         /*
1417          * DECRQTSR - request-terminal-state-report
1418          *
1419          * Probably not worth implementing.
1420          */
1421
1422         return 0;
1423 }
1424
1425 static int screen_DECRQUPSS(term_screen *screen, const term_seq *seq) {
1426         /*
1427          * DECRQUPSS - request-user-preferred-supplemental-set
1428          *
1429          * Probably not worth implementing.
1430          */
1431
1432         return 0;
1433 }
1434
1435 static int screen_DECSACE(term_screen *screen, const term_seq *seq) {
1436         /*
1437          * DECSACE - select-attribute-change-extent
1438          *
1439          * Probably not worth implementing.
1440          */
1441
1442         return 0;
1443 }
1444
1445 static int screen_DECSASD(term_screen *screen, const term_seq *seq) {
1446         /*
1447          * DECSASD - select-active-status-display
1448          *
1449          * Probably not worth implementing.
1450          */
1451
1452         return 0;
1453 }
1454
1455 static int screen_DECSC(term_screen *screen, const term_seq *seq) {
1456         /*
1457          * DECSC - save-cursor
1458          * Save cursor and terminal state so it can be restored later on.
1459          * Saves the following items in the terminal's memory:
1460          *   * Cursor position
1461          *   * Character attributes set by the SGR command
1462          *   * Character sets (G0, G1, G2, or G3) currently in GL and GR
1463          *   * Wrap flag (autowrap or no autowrap)
1464          *   * State of origin mode (DECOM)
1465          *   * Selective erase attribute
1466          *   * Any single shift 2 (SS2) or single shift 3 (SS3) functions sent
1467          */
1468
1469         screen->saved.cursor_x = screen->cursor_x;
1470         screen->saved.cursor_y = screen->cursor_y;
1471         screen->saved.attr = screen->attr;
1472         screen->saved.gl = screen->gl;
1473         screen->saved.gr = screen->gr;
1474         screen->saved.glt = screen->glt;
1475         screen->saved.grt = screen->grt;
1476         screen->saved.flags = screen->flags & (TERM_FLAG_AUTO_WRAP
1477                                                | TERM_FLAG_ORIGIN_MODE);
1478
1479         return 0;
1480 }
1481
1482 static int screen_DECSCA(term_screen *screen, const term_seq *seq) {
1483         /*
1484          * DECSCA - select-character-protection-attribute
1485          * Defines the characters that come after it as erasable or not erasable
1486          * from the screen. The selective erase control functions (DECSED and
1487          * DECSEL) can only erase characters defined as erasable.
1488          *
1489          * @args[0] specifies the new mode. 0 and 2 mark any following character
1490          * as erasable, 1 marks it as not erasable.
1491          *
1492          * Defaults:
1493          *   args[0]: 0
1494          */
1495
1496         unsigned int mode = 0;
1497
1498         if (seq->args[0] > 0)
1499                 mode = seq->args[0];
1500
1501         switch (mode) {
1502         case 0:
1503         case 2:
1504                 screen->attr.protect = 0;
1505                 break;
1506         case 1:
1507                 screen->attr.protect = 1;
1508                 break;
1509         }
1510
1511         return 0;
1512 }
1513
1514 static int screen_DECSCL(term_screen *screen, const term_seq *seq) {
1515         /*
1516          * DECSCL - select-conformance-level
1517          * Select the terminal's operating level. The factory default is
1518          * level 4 (VT Level 4 mode, 7-bit controls).
1519          * When you change the conformance level, the terminal performs a hard
1520          * reset (RIS).
1521          *
1522          * @args[0] defines the conformance-level, valid values are:
1523          *   61: Level 1 (VT100)
1524          *   62: Level 2 (VT200)
1525          *   63: Level 3 (VT300)
1526          *   64: Level 4 (VT400)
1527          * @args[1] defines the 8bit-mode, valid values are:
1528          *    0: 8-bit controls
1529          *    1: 7-bit controls
1530          *    2: 8-bit controls (same as 0)
1531          *
1532          * If @args[0] is 61, then @args[1] is ignored and 7bit controls are
1533          * enforced.
1534          *
1535          * Defaults:
1536          *   args[0]: 64
1537          *   args[1]: 0
1538          */
1539
1540         unsigned int level = 64, bit = 0;
1541
1542         if (seq->n_args > 0) {
1543                 level = seq->args[0];
1544                 if (seq->n_args > 1)
1545                         bit = seq->args[1];
1546         }
1547
1548         term_screen_hard_reset(screen);
1549
1550         switch (level) {
1551         case 61:
1552                 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT100;
1553                 screen->flags |= TERM_FLAG_7BIT_MODE;
1554                 break;
1555         case 62 ... 69:
1556                 screen->conformance_level = TERM_CONFORMANCE_LEVEL_VT400;
1557                 if (bit == 1)
1558                         screen->flags |= TERM_FLAG_7BIT_MODE;
1559                 else
1560                         screen->flags &= ~TERM_FLAG_7BIT_MODE;
1561                 break;
1562         }
1563
1564         return 0;
1565 }
1566
1567 static int screen_DECSCP(term_screen *screen, const term_seq *seq) {
1568         /*
1569          * DECSCP - select-communication-port
1570          *
1571          * Probably not worth implementing.
1572          */
1573
1574         return 0;
1575 }
1576
1577 static int screen_DECSCPP(term_screen *screen, const term_seq *seq) {
1578         /*
1579          * DECSCPP - select-columns-per-page
1580          * Select columns per page. The number of rows is unaffected by this.
1581          * @args[0] selectes the number of columns (width), DEC only defines 80
1582          * and 132, but we allow any integer here. 0 is equivalent to 80.
1583          * Page content is *not* cleared and the cursor is left untouched.
1584          * However, if the page is reduced in width and the cursor would be
1585          * outside the visible region, it's set to the right border. Newly added
1586          * cells are cleared. No data is retained outside the visible region.
1587          *
1588          * Defaults:
1589          *   args[0]: 0
1590          *
1591          * TODO: implement
1592          */
1593
1594         return 0;
1595 }
1596
1597 static int screen_DECSCS(term_screen *screen, const term_seq *seq) {
1598         /*
1599          * DECSCS - select-communication-speed
1600          *
1601          * Probably not worth implementing.
1602          */
1603
1604         return 0;
1605 }
1606
1607 static int screen_DECSCUSR(term_screen *screen, const term_seq *seq) {
1608         /*
1609          * DECSCUSR - set-cursor-style
1610          * This changes the style of the cursor. @args[0] can be one of:
1611          *   0, 1: blinking block
1612          *      2: steady block
1613          *      3: blinking underline
1614          *      4: steady underline
1615          * Changing this setting does _not_ affect the cursor visibility itself.
1616          * Use DECTCEM for that.
1617          *
1618          * Defaults:
1619          *   args[0]: 0
1620          *
1621          * TODO: implement
1622          */
1623
1624         return 0;
1625 }
1626
1627 static int screen_DECSDDT(term_screen *screen, const term_seq *seq) {
1628         /*
1629          * DECSDDT - select-disconnect-delay-time
1630          *
1631          * Probably not worth implementing.
1632          */
1633
1634         return 0;
1635 }
1636
1637 static int screen_DECSDPT(term_screen *screen, const term_seq *seq) {
1638         /*
1639          * DECSDPT - select-digital-printed-data-type
1640          *
1641          * Probably not worth implementing.
1642          */
1643
1644         return 0;
1645 }
1646
1647 static int screen_DECSED(term_screen *screen, const term_seq *seq) {
1648         /*
1649          * DECSED - selective-erase-in-display
1650          * This control function erases some or all of the erasable characters
1651          * in the display. DECSED can only erase characters defined as erasable
1652          * by the DECSCA control function. DECSED works inside or outside the
1653          * scrolling margins.
1654          *
1655          * @args[0] defines which regions are erased. If it is 0, all cells from
1656          * the cursor (inclusive) till the end of the display are erase. If it
1657          * is 1, all cells from the start of the display till the cursor
1658          * (inclusive) are erased. If it is 2, all cells are erased.
1659          *
1660          * Defaults:
1661          *   args[0]: 0
1662          */
1663
1664         unsigned int mode = 0;
1665
1666         if (seq->args[0] > 0)
1667                 mode = seq->args[0];
1668
1669         switch (mode) {
1670         case 0:
1671                 term_page_erase(screen->page,
1672                                 screen->cursor_x, screen->cursor_y,
1673                                 screen->page->width, screen->page->height,
1674                                 &screen->attr, screen->age, true);
1675                 break;
1676         case 1:
1677                 term_page_erase(screen->page,
1678                                 0, 0,
1679                                 screen->cursor_x, screen->cursor_y,
1680                                 &screen->attr, screen->age, true);
1681                 break;
1682         case 2:
1683                 term_page_erase(screen->page,
1684                                 0, 0,
1685                                 screen->page->width, screen->page->height,
1686                                 &screen->attr, screen->age, true);
1687                 break;
1688         }
1689
1690         return 0;
1691 }
1692
1693 static int screen_DECSEL(term_screen *screen, const term_seq *seq) {
1694         /*
1695          * DECSEL - selective-erase-in-line
1696          * This control function erases some or all of the erasable characters
1697          * in a single line of text. DECSEL erases only those characters defined
1698          * as erasable by the DECSCA control function. DECSEL works inside or
1699          * outside the scrolling margins.
1700          *
1701          * @args[0] defines the region to be erased. If it is 0, all cells from
1702          * the cursor (inclusive) till the end of the line are erase. If it is
1703          * 1, all cells from the start of the line till the cursor (inclusive)
1704          * are erased. If it is 2, the whole line of the cursor is erased.
1705          *
1706          * Defaults:
1707          *   args[0]: 0
1708          */
1709
1710         unsigned int mode = 0;
1711
1712         if (seq->args[0] > 0)
1713                 mode = seq->args[0];
1714
1715         switch (mode) {
1716         case 0:
1717                 term_page_erase(screen->page,
1718                                 screen->cursor_x, screen->cursor_y,
1719                                 screen->page->width, screen->cursor_y,
1720                                 &screen->attr, screen->age, true);
1721                 break;
1722         case 1:
1723                 term_page_erase(screen->page,
1724                                 0, screen->cursor_y,
1725                                 screen->cursor_x, screen->cursor_y,
1726                                 &screen->attr, screen->age, true);
1727                 break;
1728         case 2:
1729                 term_page_erase(screen->page,
1730                                 0, screen->cursor_y,
1731                                 screen->page->width, screen->cursor_y,
1732                                 &screen->attr, screen->age, true);
1733                 break;
1734         }
1735
1736         return 0;
1737 }
1738
1739 static int screen_DECSERA(term_screen *screen, const term_seq *seq) {
1740         /*
1741          * DECSERA - selective-erase-rectangular-area
1742          *
1743          * Probably not worth implementing.
1744          */
1745
1746         return 0;
1747 }
1748
1749 static int screen_DECSFC(term_screen *screen, const term_seq *seq) {
1750         /*
1751          * DECSFC - select-flow-control
1752          *
1753          * Probably not worth implementing.
1754          */
1755
1756         return 0;
1757 }
1758
1759 static int screen_DECSKCV(term_screen *screen, const term_seq *seq) {
1760         /*
1761          * DECSKCV - set-key-click-volume
1762          *
1763          * Probably not worth implementing.
1764          */
1765
1766         return 0;
1767 }
1768
1769 static int screen_DECSLCK(term_screen *screen, const term_seq *seq) {
1770         /*
1771          * DECSLCK - set-lock-key-style
1772          *
1773          * Probably not worth implementing.
1774          */
1775
1776         return 0;
1777 }
1778
1779 static int screen_DECSLE(term_screen *screen, const term_seq *seq) {
1780         /*
1781          * DECSLE - select-locator-events
1782          *
1783          * TODO: implement
1784          */
1785
1786         return 0;
1787 }
1788
1789 static int screen_DECSLPP(term_screen *screen, const term_seq *seq) {
1790         /*
1791          * DECSLPP - set-lines-per-page
1792          * Set the number of lines used for the page. @args[0] specifies the
1793          * number of lines to be used. DEC only allows a limited number of
1794          * choices, however, we allow all integers. 0 is equivalent to 24.
1795          *
1796          * Defaults:
1797          *   args[0]: 0
1798          *
1799          * TODO: implement
1800          */
1801
1802         return 0;
1803 }
1804
1805 static int screen_DECSLRM_OR_SC(term_screen *screen, const term_seq *seq) {
1806         /*
1807          * DECSLRM_OR_SC - set-left-and-right-margins or save-cursor
1808          *
1809          * TODO: Detect save-cursor and run it. DECSLRM is not worth
1810          *       implementing.
1811          */
1812
1813         return 0;
1814 }
1815
1816 static int screen_DECSMBV(term_screen *screen, const term_seq *seq) {
1817         /*
1818          * DECSMBV - set-margin-bell-volume
1819          *
1820          * Probably not worth implementing.
1821          */
1822
1823         return 0;
1824 }
1825
1826 static int screen_DECSMKR(term_screen *screen, const term_seq *seq) {
1827         /*
1828          * DECSMKR - select-modifier-key-reporting
1829          *
1830          * Probably not worth implementing.
1831          */
1832
1833         return 0;
1834 }
1835
1836 static int screen_DECSNLS(term_screen *screen, const term_seq *seq) {
1837         /*
1838          * DECSNLS - set-lines-per-screen
1839          *
1840          * Probably not worth implementing.
1841          */
1842
1843         return 0;
1844 }
1845
1846 static int screen_DECSPP(term_screen *screen, const term_seq *seq) {
1847         /*
1848          * DECSPP - set-port-parameter
1849          *
1850          * Probably not worth implementing.
1851          */
1852
1853         return 0;
1854 }
1855
1856 static int screen_DECSPPCS(term_screen *screen, const term_seq *seq) {
1857         /*
1858          * DECSPPCS - select-pro-printer-character-set
1859          *
1860          * Probably not worth implementing.
1861          */
1862
1863         return 0;
1864 }
1865
1866 static int screen_DECSPRTT(term_screen *screen, const term_seq *seq) {
1867         /*
1868          * DECSPRTT - select-printer-type
1869          *
1870          * Probably not worth implementing.
1871          */
1872
1873         return 0;
1874 }
1875
1876 static int screen_DECSR(term_screen *screen, const term_seq *seq) {
1877         /*
1878          * DECSR - secure-reset
1879          *
1880          * Probably not worth implementing.
1881          */
1882
1883         return 0;
1884 }
1885
1886 static int screen_DECSRFR(term_screen *screen, const term_seq *seq) {
1887         /*
1888          * DECSRFR - select-refresh-rate
1889          *
1890          * Probably not worth implementing.
1891          */
1892
1893         return 0;
1894 }
1895
1896 static int screen_DECSSCLS(term_screen *screen, const term_seq *seq) {
1897         /*
1898          * DECSSCLS - set-scroll-speed
1899          *
1900          * Probably not worth implementing.
1901          */
1902
1903         return 0;
1904 }
1905
1906 static int screen_DECSSDT(term_screen *screen, const term_seq *seq) {
1907         /*
1908          * DECSSDT - select-status-display-line-type
1909          *
1910          * Probably not worth implementing.
1911          */
1912
1913         return 0;
1914 }
1915
1916 static int screen_DECSSL(term_screen *screen, const term_seq *seq) {
1917         /*
1918          * DECSSL - select-setup-language
1919          *
1920          * Probably not worth implementing.
1921          */
1922
1923         return 0;
1924 }
1925
1926 static int screen_DECST8C(term_screen *screen, const term_seq *seq) {
1927         /*
1928          * DECST8C - set-tab-at-every-8-columns
1929          * Clear the tab-ruler and reset it to a tab at every 8th column,
1930          * starting at 9 (though, setting a tab at 1 is fine as it has no
1931          * effect).
1932          */
1933
1934         unsigned int i;
1935
1936         for (i = 0; i < screen->page->width; i += 8)
1937                 screen->tabs[i / 8] = 0x1;
1938
1939         return 0;
1940 }
1941
1942 static int screen_DECSTBM(term_screen *screen, const term_seq *seq) {
1943         /*
1944          * DECSTBM - set-top-and-bottom-margins
1945          * This control function sets the top and bottom margins for the current
1946          * page. You cannot perform scrolling outside the margins.
1947          *
1948          * @args[0] defines the top margin, @args[1] defines the bottom margin.
1949          * The bottom margin must be lower than the top-margin.
1950          *
1951          * This call resets the cursor position to 0/0 of the page.
1952          *
1953          * Defaults:
1954          *   args[0]: 1
1955          *   args[1]: last page-line
1956          */
1957
1958         unsigned int top, bottom;
1959
1960         top = 1;
1961         bottom = screen->page->height;
1962
1963         if (seq->args[0] > 0)
1964                 top = seq->args[0];
1965         if (seq->args[1] > 0)
1966                 bottom = seq->args[1];
1967
1968         if (top > screen->page->height)
1969                 top = screen->page->height;
1970         if (bottom > screen->page->height)
1971                 bottom = screen->page->height;
1972
1973         if (top >= bottom || top > screen->page->height || bottom > screen->page->height) {
1974                 top = 1;
1975                 bottom = screen->page->height;
1976         }
1977
1978         term_page_set_scroll_region(screen->page_main, top - 1, bottom - top + 1);
1979         term_page_set_scroll_region(screen->page_alt, top - 1, bottom - top + 1);
1980         screen_cursor_clear_wrap(screen);
1981         screen_cursor_set(screen, 0, 0);
1982
1983         return 0;
1984 }
1985
1986 static int screen_DECSTR(term_screen *screen, const term_seq *seq) {
1987         /*
1988          * DECSTR - soft-terminal-reset
1989          * Perform a soft reset to the default values.
1990          */
1991
1992         term_screen_soft_reset(screen);
1993
1994         return 0;
1995 }
1996
1997 static int screen_DECSTRL(term_screen *screen, const term_seq *seq) {
1998         /*
1999          * DECSTRL - set-transmit-rate-limit
2000          *
2001          * Probably not worth implementing.
2002          */
2003
2004         return 0;
2005 }
2006
2007 static int screen_DECSWBV(term_screen *screen, const term_seq *seq) {
2008         /*
2009          * DECSWBV - set-warning-bell-volume
2010          *
2011          * Probably not worth implementing.
2012          */
2013
2014         return 0;
2015 }
2016
2017 static int screen_DECSWL(term_screen *screen, const term_seq *seq) {
2018         /*
2019          * DECSWL - single-width-single-height-line
2020          *
2021          * Probably not worth implementing.
2022          */
2023
2024         return 0;
2025 }
2026
2027 static int screen_DECTID(term_screen *screen, const term_seq *seq) {
2028         /*
2029          * DECTID - select-terminal-id
2030          *
2031          * Probably not worth implementing.
2032          */
2033
2034         return 0;
2035 }
2036
2037 static int screen_DECTME(term_screen *screen, const term_seq *seq) {
2038         /*
2039          * DECTME - terminal-mode-emulation
2040          *
2041          * Probably not worth implementing.
2042          */
2043
2044         return 0;
2045 }
2046
2047 static int screen_DECTST(term_screen *screen, const term_seq *seq) {
2048         /*
2049          * DECTST - invoke-confidence-test
2050          *
2051          * Probably not worth implementing.
2052          */
2053
2054         return 0;
2055 }
2056
2057 static int screen_DL(term_screen *screen, const term_seq *seq) {
2058         /*
2059          * DL - delete-line
2060          * This control function deletes one or more lines in the scrolling
2061          * region, starting with the line that has the cursor. @args[0] defines
2062          * the number of lines to delete. 0 is treated the same as 1.
2063          * As lines are deleted, lines below the cursor and in the scrolling
2064          * region move up. The terminal adds blank lines with no visual
2065          * character attributes at the bottom of the scrolling region. If it is
2066          * greater than the number of lines remaining on the page, DL deletes
2067          * only the remaining lines. DL has no effect outside the scrolling
2068          * margins.
2069          *
2070          * Defaults:
2071          *   args[0]: 1
2072          */
2073
2074         unsigned int num = 1;
2075
2076         if (seq->args[0] > 0)
2077                 num = seq->args[0];
2078
2079         term_page_delete_lines(screen->page, screen->cursor_y, num, &screen->attr, screen->age);
2080
2081         return 0;
2082 }
2083
2084 static int screen_DSR_ANSI(term_screen *screen, const term_seq *seq) {
2085         /*
2086          * DSR_ANSI - device-status-report-ansi
2087          *
2088          * TODO: implement
2089          */
2090
2091         return 0;
2092 }
2093
2094 static int screen_DSR_DEC(term_screen *screen, const term_seq *seq) {
2095         /*
2096          * DSR_DEC - device-status-report-dec
2097          *
2098          * TODO: implement
2099          */
2100
2101         return 0;
2102 }
2103
2104 static int screen_ECH(term_screen *screen, const term_seq *seq) {
2105         /*
2106          * ECH - erase-character
2107          * This control function erases one or more characters, from the cursor
2108          * position to the right. ECH clears character attributes from erased
2109          * character positions. ECH works inside or outside the scrolling
2110          * margins.
2111          * @args[0] defines the number of characters to erase. 0 is treated the
2112          * same as 1.
2113          *
2114          * Defaults:
2115          *   args[0]: 1
2116          */
2117
2118         unsigned int num = 1;
2119
2120         if (seq->args[0] > 0)
2121                 num = seq->args[0];
2122
2123         term_page_erase(screen->page,
2124                         screen->cursor_x, screen->cursor_y,
2125                         screen->cursor_x + num, screen->cursor_y,
2126                         &screen->attr, screen->age, false);
2127
2128         return 0;
2129 }
2130
2131 static int screen_ED(term_screen *screen, const term_seq *seq) {
2132         /*
2133          * ED - erase-in-display
2134          * This control function erases characters from part or all of the
2135          * display. When you erase complete lines, they become single-height,
2136          * single-width lines, with all visual character attributes cleared. ED
2137          * works inside or outside the scrolling margins.
2138          *
2139          * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2140          * till the end of the screen. 1 means from the start of the screen till
2141          * the cursor (inclusive) and 2 means the whole screen.
2142          *
2143          * Defaults:
2144          *   args[0]: 0
2145          */
2146
2147         unsigned int mode = 0;
2148
2149         if (seq->args[0] > 0)
2150                 mode = seq->args[0];
2151
2152         switch (mode) {
2153         case 0:
2154                 term_page_erase(screen->page,
2155                                 screen->cursor_x, screen->cursor_y,
2156                                 screen->page->width, screen->page->height,
2157                                 &screen->attr, screen->age, false);
2158                 break;
2159         case 1:
2160                 term_page_erase(screen->page,
2161                                 0, 0,
2162                                 screen->cursor_x, screen->cursor_y,
2163                                 &screen->attr, screen->age, false);
2164                 break;
2165         case 2:
2166                 term_page_erase(screen->page,
2167                                 0, 0,
2168                                 screen->page->width, screen->page->height,
2169                                 &screen->attr, screen->age, false);
2170                 break;
2171         }
2172
2173         return 0;
2174 }
2175
2176 static int screen_EL(term_screen *screen, const term_seq *seq) {
2177         /*
2178          * EL - erase-in-line
2179          * This control function erases characters on the line that has the
2180          * cursor. EL clears all character attributes from erased character
2181          * positions. EL works inside or outside the scrolling margins.
2182          *
2183          * @args[0] defines the region to erase. 0 means from cursor (inclusive)
2184          * till the end of the line. 1 means from the start of the line till the
2185          * cursor (inclusive) and 2 means the whole line.
2186          *
2187          * Defaults:
2188          *   args[0]: 0
2189          */
2190
2191         unsigned int mode = 0;
2192
2193         if (seq->args[0] > 0)
2194                 mode = seq->args[0];
2195
2196         switch (mode) {
2197         case 0:
2198                 term_page_erase(screen->page,
2199                                 screen->cursor_x, screen->cursor_y,
2200                                 screen->page->width, screen->cursor_y,
2201                                 &screen->attr, screen->age, false);
2202                 break;
2203         case 1:
2204                 term_page_erase(screen->page,
2205                                 0, screen->cursor_y,
2206                                 screen->cursor_x, screen->cursor_y,
2207                                 &screen->attr, screen->age, false);
2208                 break;
2209         case 2:
2210                 term_page_erase(screen->page,
2211                                 0, screen->cursor_y,
2212                                 screen->page->width, screen->cursor_y,
2213                                 &screen->attr, screen->age, false);
2214                 break;
2215         }
2216
2217         return 0;
2218 }
2219
2220 static int screen_ENQ(term_screen *screen, const term_seq *seq) {
2221         /*
2222          * ENQ - enquiry
2223          * Transmit the answerback-string. If none is set, do nothing.
2224          */
2225
2226         if (screen->answerback)
2227                 return screen_write(screen, screen->answerback, strlen(screen->answerback));
2228
2229         return 0;
2230 }
2231
2232 static int screen_EPA(term_screen *screen, const term_seq *seq) {
2233         /*
2234          * EPA - end-of-guarded-area
2235          *
2236          * TODO: What is this?
2237          */
2238
2239         return 0;
2240 }
2241
2242 static int screen_FF(term_screen *screen, const term_seq *seq) {
2243         /*
2244          * FF - form-feed
2245          * This causes the cursor to jump to the next line. It is treated the
2246          * same as LF.
2247          */
2248
2249         return screen_LF(screen, seq);
2250 }
2251
2252 static int screen_HPA(term_screen *screen, const term_seq *seq) {
2253         /*
2254          * HPA - horizontal-position-absolute
2255          * HPA causes the active position to be moved to the n-th horizontal
2256          * position of the active line. If an attempt is made to move the active
2257          * position past the last position on the line, then the active position
2258          * stops at the last position on the line.
2259          *
2260          * @args[0] defines the horizontal position. 0 is treated as 1.
2261          *
2262          * Defaults:
2263          *   args[0]: 1
2264          */
2265
2266         unsigned int num = 1;
2267
2268         if (seq->args[0] > 0)
2269                 num = seq->args[0];
2270
2271         screen_cursor_clear_wrap(screen);
2272         screen_cursor_set(screen, num - 1, screen->cursor_y);
2273
2274         return 0;
2275 }
2276
2277 static int screen_HPR(term_screen *screen, const term_seq *seq) {
2278         /*
2279          * HPR - horizontal-position-relative
2280          * HPR causes the active position to be moved to the n-th following
2281          * horizontal position of the active line. If an attempt is made to move
2282          * the active position past the last position on the line, then the
2283          * active position stops at the last position on the line.
2284          *
2285          * @args[0] defines the horizontal position. 0 is treated as 1.
2286          *
2287          * Defaults:
2288          *   args[0]: 1
2289          */
2290
2291         unsigned int num = 1;
2292
2293         if (seq->args[0] > 0)
2294                 num = seq->args[0];
2295
2296         screen_cursor_clear_wrap(screen);
2297         screen_cursor_right(screen, num);
2298
2299         return 0;
2300 }
2301
2302 static int screen_HT(term_screen *screen, const term_seq *seq) {
2303         /*
2304          * HT - horizontal-tab
2305          * Moves the cursor to the next tab stop. If there are no more tab
2306          * stops, the cursor moves to the right margin. HT does not cause text
2307          * to auto wrap.
2308          */
2309
2310         screen_cursor_clear_wrap(screen);
2311         screen_cursor_right_tab(screen, 1);
2312
2313         return 0;
2314 }
2315
2316 static int screen_HTS(term_screen *screen, const term_seq *seq) {
2317         /*
2318          * HTS - horizontal-tab-set
2319          * HTS sets a horizontal tab stop at the column position indicated by
2320          * the value of the active column when the terminal receives an HTS.
2321          *
2322          * Executing an HTS does not effect the other horizontal tab stop
2323          * settings.
2324          */
2325
2326         unsigned int pos;
2327
2328         pos = screen->cursor_x;
2329         if (screen->page->width > 0)
2330                 screen->tabs[pos / 8] |= 1U << (pos % 8);
2331
2332         return 0;
2333 }
2334
2335 static int screen_HVP(term_screen *screen, const term_seq *seq) {
2336         /*
2337          * HVP - horizontal-and-vertical-position
2338          * This control function works the same as the cursor position (CUP)
2339          * function. Origin mode (DECOM) selects line numbering and the ability
2340          * to move the cursor into margins.
2341          *
2342          * Defaults:
2343          *   args[0]: 1
2344          *   args[1]: 1
2345          */
2346
2347         return screen_CUP(screen, seq);
2348 }
2349
2350 static int screen_ICH(term_screen *screen, const term_seq *seq) {
2351         /*
2352          * ICH - insert-character
2353          * This control function inserts one or more space (SP) characters
2354          * starting at the cursor position. @args[0] is the number of characters
2355          * to insert. 0 is treated as 1.
2356          *
2357          * The ICH sequence inserts blank characters with the normal
2358          * character attribute. The cursor remains at the beginning of the blank
2359          * characters. Text between the cursor and right margin moves to the
2360          * right. Characters scrolled past the right margin are lost. ICH has no
2361          * effect outside the scrolling margins.
2362          *
2363          * Defaults:
2364          *   args[0]: 1
2365          */
2366
2367         unsigned int num = 1;
2368
2369         if (seq->args[0] > 0)
2370                 num = seq->args[0];
2371
2372         screen_cursor_clear_wrap(screen);
2373         term_page_insert_cells(screen->page, screen->cursor_x, screen->cursor_y, num, &screen->attr, screen->age);
2374
2375         return 0;
2376 }
2377
2378 static int screen_IL(term_screen *screen, const term_seq *seq) {
2379         /*
2380          * IL - insert-line
2381          * This control function inserts one or more blank lines, starting at
2382          * the cursor. @args[0] is the number of lines to insert. 0 is treated
2383          * as 1.
2384          *
2385          * As lines are inserted, lines below the cursor and in the scrolling
2386          * region move down. Lines scrolled off the page are lost. IL has no
2387          * effect outside the page margins.
2388          *
2389          * Defaults:
2390          *   args[0]: 1
2391          */
2392
2393         unsigned int num = 1;
2394
2395         if (seq->args[0] > 0)
2396                 num = seq->args[0];
2397
2398         screen_cursor_clear_wrap(screen);
2399         term_page_insert_lines(screen->page, screen->cursor_y, num, &screen->attr, screen->age);
2400
2401         return 0;
2402 }
2403
2404 static int screen_IND(term_screen *screen, const term_seq *seq) {
2405         /*
2406          * IND - index
2407          * IND moves the cursor down one line in the same column. If the cursor
2408          * is at the bottom margin, then the screen performs a scroll-up.
2409          */
2410
2411         screen_cursor_down(screen, 1, true);
2412
2413         return 0;
2414 }
2415
2416 static int screen_LF(term_screen *screen, const term_seq *seq) {
2417         /*
2418          * LF - line-feed
2419          * Causes a line feed or a new line operation, depending on the setting
2420          * of line feed/new line mode.
2421          */
2422
2423         screen_cursor_down(screen, 1, true);
2424         if (screen->flags & TERM_FLAG_NEWLINE_MODE)
2425                 screen_cursor_left(screen, screen->cursor_x);
2426
2427         return 0;
2428 }
2429
2430 static int screen_LS1R(term_screen *screen, const term_seq *seq) {
2431         /*
2432          * LS1R - locking-shift-1-right
2433          * Map G1 into GR.
2434          */
2435
2436         screen->gr = &screen->g1;
2437
2438         return 0;
2439 }
2440
2441 static int screen_LS2(term_screen *screen, const term_seq *seq) {
2442         /*
2443          * LS2 - locking-shift-2
2444          * Map G2 into GL.
2445          */
2446
2447         screen->gl = &screen->g2;
2448
2449         return 0;
2450 }
2451
2452 static int screen_LS2R(term_screen *screen, const term_seq *seq) {
2453         /*
2454          * LS2R - locking-shift-2-right
2455          * Map G2 into GR.
2456          */
2457
2458         screen->gr = &screen->g2;
2459
2460         return 0;
2461 }
2462
2463 static int screen_LS3(term_screen *screen, const term_seq *seq) {
2464         /*
2465          * LS3 - locking-shift-3
2466          * Map G3 into GL.
2467          */
2468
2469         screen->gl = &screen->g3;
2470
2471         return 0;
2472 }
2473
2474 static int screen_LS3R(term_screen *screen, const term_seq *seq) {
2475         /*
2476          * LS3R - locking-shift-3-right
2477          * Map G3 into GR.
2478          */
2479
2480         screen->gr = &screen->g3;
2481
2482         return 0;
2483 }
2484
2485 static int screen_MC_ANSI(term_screen *screen, const term_seq *seq) {
2486         /*
2487          * MC_ANSI - media-copy-ansi
2488          *
2489          * Probably not worth implementing.
2490          */
2491
2492         return 0;
2493 }
2494
2495 static int screen_MC_DEC(term_screen *screen, const term_seq *seq) {
2496         /*
2497          * MC_DEC - media-copy-dec
2498          *
2499          * Probably not worth implementing.
2500          */
2501
2502         return 0;
2503 }
2504
2505 static int screen_NEL(term_screen *screen, const term_seq *seq) {
2506         /*
2507          * NEL - next-line
2508          * Moves cursor to first position on next line. If cursor is at bottom
2509          * margin, then screen performs a scroll-up.
2510          */
2511
2512         screen_cursor_clear_wrap(screen);
2513         screen_cursor_down(screen, 1, true);
2514         screen_cursor_set(screen, 0, screen->cursor_y);
2515
2516         return 0;
2517 }
2518
2519 static int screen_NP(term_screen *screen, const term_seq *seq) {
2520         /*
2521          * NP - next-page
2522          * This control function moves the cursor forward to the home position
2523          * on one of the following pages in page memory. If there is only one
2524          * page, then the terminal ignores NP.
2525          * If NP tries to move the cursor past the last page in memory, then the
2526          * cursor stops at the last page.
2527          *
2528          * @args[0] defines the number of pages to forward. 0 is treated as 1.
2529          *
2530          * Defaults:
2531          *   args[0]: 1
2532          *
2533          * Probably not worth implementing. We only support a single page.
2534          */
2535
2536         return 0;
2537 }
2538
2539 static int screen_NULL(term_screen *screen, const term_seq *seq) {
2540         /*
2541          * NULL - null
2542          * The NULL operation does nothing. ASCII NULL is always ignored.
2543          */
2544
2545         return 0;
2546 }
2547
2548 static int screen_PP(term_screen *screen, const term_seq *seq) {
2549         /*
2550          * PP - preceding-page
2551          * This control function moves the cursor backward to the home position
2552          * on one of the preceding pages in page memory. If there is only one
2553          * page, then the terminal ignores PP.
2554          * If PP tries to move the cursor back farther than the first page in
2555          * memory, then the cursor stops at the first page.
2556          *
2557          * @args[0] defines the number of pages to go backwards. 0 is treated
2558          * as 1.
2559          *
2560          * Defaults:
2561          *   args[0]: 1
2562          *
2563          * Probably not worth implementing. We only support a single page.
2564          */
2565
2566         return 0;
2567 }
2568
2569 static int screen_PPA(term_screen *screen, const term_seq *seq) {
2570         /*
2571          * PPA - page-position-absolute
2572          * This control function can move the cursor to the corresponding row
2573          * and column on any page in page memory. You select the page by its
2574          * number. If there is only one page, then the terminal ignores PPA.
2575          *
2576          * @args[0] is the number of the page to move the cursor to. If it is
2577          * greater than the number of the last page in memory, then the cursor
2578          * stops at the last page. If it is less than the number of the first
2579          * page, then the cursor stops at the first page.
2580          *
2581          * Defaults:
2582          *   args[0]: 1
2583          *
2584          * Probably not worth implementing. We only support a single page.
2585          */
2586
2587         return 0;
2588 }
2589
2590 static int screen_PPB(term_screen *screen, const term_seq *seq) {
2591         /*
2592          * PPB - page-position-backward
2593          * This control function moves the cursor backward to the corresponding
2594          * row and column on one of the preceding pages in page memory. If there
2595          * is only one page, then the terminal ignores PPB.
2596          *
2597          * @args[0] indicates the number of pages to move the cursor backward.
2598          * If it tries to move the cursor back farther than the first page in
2599          * memory, then the cursor stops at the first page. 0 is treated as 1.
2600          *
2601          * Defaults:
2602          *   args[0]: 1
2603          *
2604          * Probably not worth implementing. We only support a single page.
2605          */
2606
2607         return 0;
2608 }
2609
2610 static int screen_PPR(term_screen *screen, const term_seq *seq) {
2611         /*
2612          * PPR - page-position-relative
2613          * This control function moves the cursor forward to the corresponding
2614          * row and column on one of the following pages in page memory. If there
2615          * is only one page, then the terminal ignores PPR.
2616          *
2617          * @args[0] indicates how many pages to move the cursor forward. If it
2618          * tries to move the cursor beyond the last page in memory, then the
2619          * cursor stops at the last page. 0 is treated as 1.
2620          *
2621          * Defaults:
2622          *   args[0]: 1
2623          *
2624          * Probably not worth implementing. We only support a single page.
2625          */
2626
2627         return 0;
2628 }
2629
2630 static int screen_RC(term_screen *screen, const term_seq *seq) {
2631         /*
2632          * RC - restore-cursor
2633          */
2634
2635         return screen_DECRC(screen, seq);
2636 }
2637
2638 static int screen_REP(term_screen *screen, const term_seq *seq) {
2639         /*
2640          * REP - repeat
2641          * Repeat the preceding graphics-character the given number of times.
2642          * @args[0] specifies how often it shall be repeated. 0 is treated as 1.
2643          *
2644          * Defaults:
2645          *   args[0]: 1
2646          *
2647          * Probably not worth implementing.
2648          */
2649
2650         return 0;
2651 }
2652
2653 static int screen_RI(term_screen *screen, const term_seq *seq) {
2654         /*
2655          * RI - reverse-index
2656          * Moves the cursor up one line in the same column. If the cursor is at
2657          * the top margin, the page scrolls down.
2658          */
2659
2660         screen_cursor_up(screen, 1, true);
2661
2662         return 0;
2663 }
2664
2665 static int screen_RIS(term_screen *screen, const term_seq *seq) {
2666         /*
2667          * RIS - reset-to-initial-state
2668          * This control function causes a nonvolatile memory (NVR) recall to
2669          * occur. RIS replaces all set-up features with their saved settings.
2670          *
2671          * The terminal stores these saved settings in NVR memory. The saved
2672          * setting for a feature is the same as the factory-default setting,
2673          * unless you saved a new setting.
2674          */
2675
2676         term_screen_hard_reset(screen);
2677
2678         return 0;
2679 }
2680
2681 static int screen_RM_ANSI(term_screen *screen, const term_seq *seq) {
2682         /*
2683          * RM_ANSI - reset-mode-ansi
2684          *
2685          * TODO: implement (see VT510rm manual)
2686          */
2687
2688         unsigned int i;
2689
2690         for (i = 0; i < seq->n_args; ++i)
2691                 screen_mode_change(screen, seq->args[i], false, false);
2692
2693         return 0;
2694 }
2695
2696 static int screen_RM_DEC(term_screen *screen, const term_seq *seq) {
2697         /*
2698          * RM_DEC - reset-mode-dec
2699          * This is the same as RM_ANSI but for DEC modes.
2700          */
2701
2702         unsigned int i;
2703
2704         for (i = 0; i < seq->n_args; ++i)
2705                 screen_mode_change(screen, seq->args[i], true, false);
2706
2707         return 0;
2708 }
2709
2710 static int screen_S7C1T(term_screen *screen, const term_seq *seq) {
2711         /*
2712          * S7C1T - set-7bit-c1-terminal
2713          * This causes the terminal to start sending C1 controls as 7bit
2714          * sequences instead of 8bit C1 controls.
2715          * This is ignored if the terminal is below level-2 emulation mode
2716          * (VT100 and below), the terminal already sends 7bit controls then.
2717          */
2718
2719         if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2720                 screen->flags |= TERM_FLAG_7BIT_MODE;
2721
2722         return 0;
2723 }
2724
2725 static int screen_S8C1T(term_screen *screen, const term_seq *seq) {
2726         /*
2727          * S8C1T - set-8bit-c1-terminal
2728          * This causes the terminal to start sending C1 controls as 8bit C1
2729          * control instead of 7bit sequences.
2730          * This is ignored if the terminal is below level-2 emulation mode
2731          * (VT100 and below). The terminal always sends 7bit controls in those
2732          * modes.
2733          */
2734
2735         if (screen->conformance_level > TERM_CONFORMANCE_LEVEL_VT100)
2736                 screen->flags &= ~TERM_FLAG_7BIT_MODE;
2737
2738         return 0;
2739 }
2740
2741 static int screen_SCS(term_screen *screen, const term_seq *seq) {
2742         /*
2743          * SCS - select-character-set
2744          * Designate character sets to G-sets. The mapping from intermediates
2745          * and terminal characters in the escape sequence to G-sets and
2746          * character-sets is non-trivial and implemented separately. See there
2747          * for more information.
2748          * This call simply sets the selected G-set to the desired
2749          * character-set.
2750          */
2751
2752         term_charset *cs = NULL;
2753
2754         /* TODO: support more of them? */
2755         switch (seq->charset) {
2756         case TERM_CHARSET_ISO_LATIN1_SUPPLEMENTAL:
2757         case TERM_CHARSET_ISO_LATIN2_SUPPLEMENTAL:
2758         case TERM_CHARSET_ISO_LATIN5_SUPPLEMENTAL:
2759         case TERM_CHARSET_ISO_GREEK_SUPPLEMENTAL:
2760         case TERM_CHARSET_ISO_HEBREW_SUPPLEMENTAL:
2761         case TERM_CHARSET_ISO_LATIN_CYRILLIC:
2762                 break;
2763
2764         case TERM_CHARSET_DEC_SPECIAL_GRAPHIC:
2765                 cs = &term_dec_special_graphics;
2766                 break;
2767         case TERM_CHARSET_DEC_SUPPLEMENTAL:
2768                 cs = &term_dec_supplemental_graphics;
2769                 break;
2770         case TERM_CHARSET_DEC_TECHNICAL:
2771         case TERM_CHARSET_CYRILLIC_DEC:
2772         case TERM_CHARSET_DUTCH_NRCS:
2773         case TERM_CHARSET_FINNISH_NRCS:
2774         case TERM_CHARSET_FRENCH_NRCS:
2775         case TERM_CHARSET_FRENCH_CANADIAN_NRCS:
2776         case TERM_CHARSET_GERMAN_NRCS:
2777         case TERM_CHARSET_GREEK_DEC:
2778         case TERM_CHARSET_GREEK_NRCS:
2779         case TERM_CHARSET_HEBREW_DEC:
2780         case TERM_CHARSET_HEBREW_NRCS:
2781         case TERM_CHARSET_ITALIAN_NRCS:
2782         case TERM_CHARSET_NORWEGIAN_DANISH_NRCS:
2783         case TERM_CHARSET_PORTUGUESE_NRCS:
2784         case TERM_CHARSET_RUSSIAN_NRCS:
2785         case TERM_CHARSET_SCS_NRCS:
2786         case TERM_CHARSET_SPANISH_NRCS:
2787         case TERM_CHARSET_SWEDISH_NRCS:
2788         case TERM_CHARSET_SWISS_NRCS:
2789         case TERM_CHARSET_TURKISH_DEC:
2790         case TERM_CHARSET_TURKISH_NRCS:
2791                 break;
2792
2793         case TERM_CHARSET_USERPREF_SUPPLEMENTAL:
2794                 break;
2795         }
2796
2797         if (seq->intermediates & TERM_SEQ_FLAG_POPEN)
2798                 screen->g0 = cs ? : &term_unicode_lower;
2799         else if (seq->intermediates & TERM_SEQ_FLAG_PCLOSE)
2800                 screen->g1 = cs ? : &term_unicode_upper;
2801         else if (seq->intermediates & TERM_SEQ_FLAG_MULT)
2802                 screen->g2 = cs ? : &term_unicode_lower;
2803         else if (seq->intermediates & TERM_SEQ_FLAG_PLUS)
2804                 screen->g3 = cs ? : &term_unicode_upper;
2805         else if (seq->intermediates & TERM_SEQ_FLAG_MINUS)
2806                 screen->g1 = cs ? : &term_unicode_upper;
2807         else if (seq->intermediates & TERM_SEQ_FLAG_DOT)
2808                 screen->g2 = cs ? : &term_unicode_lower;
2809         else if (seq->intermediates & TERM_SEQ_FLAG_SLASH)
2810                 screen->g3 = cs ? : &term_unicode_upper;
2811
2812         return 0;
2813 }
2814
2815 static int screen_SD(term_screen *screen, const term_seq *seq) {
2816         /*
2817          * SD - scroll-down
2818          * This control function moves the user window down a specified number
2819          * of lines in page memory.
2820          * @args[0] is the number of lines to move the
2821          * user window up in page memory. New lines appear at the top of the
2822          * display. Old lines disappear at the bottom of the display. You
2823          * cannot pan past the top margin of the current page. 0 is treated
2824          * as 1.
2825          *
2826          * Defaults:
2827          *   args[0]: 1
2828          */
2829
2830         unsigned int num = 1;
2831
2832         if (seq->args[0] > 0)
2833                 num = seq->args[0];
2834
2835         term_page_scroll_down(screen->page, num, &screen->attr, screen->age, NULL);
2836
2837         return 0;
2838 }
2839
2840 static int screen_SGR(term_screen *screen, const term_seq *seq) {
2841         /*
2842          * SGR - select-graphics-rendition
2843          */
2844
2845         term_color *dst;
2846         unsigned int i, code;
2847         int v;
2848
2849         if (seq->n_args < 1) {
2850                 zero(screen->attr);
2851                 return 0;
2852         }
2853
2854         for (i = 0; i < seq->n_args; ++i) {
2855                 v = seq->args[i];
2856                 switch (v) {
2857                 case 1:
2858                         screen->attr.bold = 1;
2859                         break;
2860                 case 3:
2861                         screen->attr.italic = 1;
2862                         break;
2863                 case 4:
2864                         screen->attr.underline = 1;
2865                         break;
2866                 case 5:
2867                         screen->attr.blink = 1;
2868                         break;
2869                 case 7:
2870                         screen->attr.inverse = 1;
2871                         break;
2872                 case 8:
2873                         screen->attr.hidden = 1;
2874                         break;
2875                 case 22:
2876                         screen->attr.bold = 0;
2877                         break;
2878                 case 23:
2879                         screen->attr.italic = 0;
2880                         break;
2881                 case 24:
2882                         screen->attr.underline = 0;
2883                         break;
2884                 case 25:
2885                         screen->attr.blink = 0;
2886                         break;
2887                 case 27:
2888                         screen->attr.inverse = 0;
2889                         break;
2890                 case 28:
2891                         screen->attr.hidden = 0;
2892                         break;
2893                 case 30 ... 37:
2894                         screen->attr.fg.ccode = v - 30 + TERM_CCODE_BLACK;
2895                         break;
2896                 case 39:
2897                         screen->attr.fg.ccode = 0;
2898                         break;
2899                 case 40 ... 47:
2900                         screen->attr.bg.ccode = v - 40 + TERM_CCODE_BLACK;
2901                         break;
2902                 case 49:
2903                         screen->attr.bg.ccode = 0;
2904                         break;
2905                 case 90 ... 97:
2906                         screen->attr.fg.ccode = v - 90 + TERM_CCODE_LIGHT_BLACK;
2907                         break;
2908                 case 100 ... 107:
2909                         screen->attr.bg.ccode = v - 100 + TERM_CCODE_LIGHT_BLACK;
2910                         break;
2911                 case 38:
2912                         /* fallthrough */
2913                 case 48:
2914
2915                         if (v == 38)
2916                                 dst = &screen->attr.fg;
2917                         else
2918                                 dst = &screen->attr.bg;
2919
2920                         ++i;
2921                         if (i >= seq->n_args)
2922                                 break;
2923
2924                         switch (seq->args[i]) {
2925                         case 2:
2926                                 /* 24bit-color support */
2927
2928                                 i += 3;
2929                                 if (i >= seq->n_args)
2930                                         break;
2931
2932                                 dst->ccode = TERM_CCODE_RGB;
2933                                 dst->red = (seq->args[i - 2] >= 0) ? seq->args[i - 2] : 0;
2934                                 dst->green = (seq->args[i - 1] >= 0) ? seq->args[i - 1] : 0;
2935                                 dst->blue = (seq->args[i] >= 0) ? seq->args[i] : 0;
2936
2937                                 break;
2938                         case 5:
2939                                 /* 256-color support */
2940
2941                                 ++i;
2942                                 if (i >= seq->n_args || seq->args[i] < 0)
2943                                         break;
2944
2945                                 code = seq->args[i];
2946                                 if (code < 16) {
2947                                         dst->ccode = code;
2948                                 } else if (code < 232) {
2949                                         static const uint8_t bval[] = {
2950                                                 0x00, 0x5f, 0x87,
2951                                                 0xaf, 0xd7, 0xff,
2952                                         };
2953
2954                                         dst->ccode = TERM_CCODE_256;
2955                                         dst->c256 = code;
2956                                         code -= 16;
2957                                         dst->blue = bval[code % 6];
2958                                         code /= 6;
2959                                         dst->green = bval[code % 6];
2960                                         code /= 6;
2961                                         dst->red = bval[code % 6];
2962                                 } else if (code < 256) {
2963                                         dst->ccode = TERM_CCODE_256;
2964                                         dst->c256 = code;
2965                                         code = (code - 232) * 10 + 8;
2966                                         dst->red = code;
2967                                         dst->green = code;
2968                                         dst->blue = code;
2969                                 }
2970
2971                                 break;
2972                         }
2973
2974                         break;
2975                 case -1:
2976                         /* fallthrough */
2977                 case 0:
2978                         zero(screen->attr);
2979                         break;
2980                 }
2981         }
2982
2983         return 0;
2984 }
2985
2986 static int screen_SI(term_screen *screen, const term_seq *seq) {
2987         /*
2988          * SI - shift-in
2989          * Map G0 into GL.
2990          */
2991
2992         screen->gl = &screen->g0;
2993
2994         return 0;
2995 }
2996
2997 static int screen_SM_ANSI(term_screen *screen, const term_seq *seq) {
2998         /*
2999          * SM_ANSI - set-mode-ansi
3000          *
3001          * TODO: implement
3002          */
3003
3004         unsigned int i;
3005
3006         for (i = 0; i < seq->n_args; ++i)
3007                 screen_mode_change(screen, seq->args[i], false, true);
3008
3009         return 0;
3010 }
3011
3012 static int screen_SM_DEC(term_screen *screen, const term_seq *seq) {
3013         /*
3014          * SM_DEC - set-mode-dec
3015          * This is the same as SM_ANSI but for DEC modes.
3016          */
3017
3018         unsigned int i;
3019
3020         for (i = 0; i < seq->n_args; ++i)
3021                 screen_mode_change(screen, seq->args[i], true, true);
3022
3023         return 0;
3024 }
3025
3026 static int screen_SO(term_screen *screen, const term_seq *seq) {
3027         /*
3028          * SO - shift-out
3029          * Map G1 into GL.
3030          */
3031
3032         screen->gl = &screen->g1;
3033
3034         return 0;
3035 }
3036
3037 static int screen_SPA(term_screen *screen, const term_seq *seq) {
3038         /*
3039          * SPA - start-of-protected-area
3040          *
3041          * TODO: What is this?
3042          */
3043
3044         return 0;
3045 }
3046
3047 static int screen_SS2(term_screen *screen, const term_seq *seq) {
3048         /*
3049          * SS2 - single-shift-2
3050          * Temporarily map G2 into GL for the next graphics character.
3051          */
3052
3053         screen->glt = &screen->g2;
3054
3055         return 0;
3056 }
3057
3058 static int screen_SS3(term_screen *screen, const term_seq *seq) {
3059         /*
3060          * SS3 - single-shift-3
3061          * Temporarily map G3 into GL for the next graphics character
3062          */
3063
3064         screen->glt = &screen->g3;
3065
3066         return 0;
3067 }
3068
3069 static int screen_ST(term_screen *screen, const term_seq *seq) {
3070         /*
3071          * ST - string-terminator
3072          * The string-terminator is usually part of control-sequences and
3073          * handled by the parser. In all other situations it is silently
3074          * ignored.
3075          */
3076
3077         return 0;
3078 }
3079
3080 static int screen_SU(term_screen *screen, const term_seq *seq) {
3081         /*
3082          * SU - scroll-up
3083          * This control function moves the user window up a specified number of
3084          * lines in page memory.
3085          * @args[0] is the number of lines to move the
3086          * user window down in page memory. New lines appear at the bottom of
3087          * the display. Old lines disappear at the top of the display. You
3088          * cannot pan past the bottom margin of the current page. 0 is treated
3089          * as 1.
3090          *
3091          * Defaults:
3092          *   args[0]: 1
3093          */
3094
3095         unsigned int num = 1;
3096
3097         if (seq->args[0] > 0)
3098                 num = seq->args[0];
3099
3100         term_page_scroll_up(screen->page, num, &screen->attr, screen->age, screen->history);
3101
3102         return 0;
3103 }
3104
3105 static int screen_SUB(term_screen *screen, const term_seq *seq) {
3106         /*
3107          * SUB - substitute
3108          * Cancel the current control-sequence and print a replacement
3109          * character. Our parser already handles this so all we have to do is
3110          * print the replacement character.
3111          */
3112
3113         static const term_seq rep = {
3114                 .type = TERM_SEQ_GRAPHIC,
3115                 .command = TERM_CMD_GRAPHIC,
3116                 .terminator = 0xfffd,
3117         };
3118
3119         return screen_GRAPHIC(screen, &rep);
3120 }
3121
3122 static int screen_TBC(term_screen *screen, const term_seq *seq) {
3123         /*
3124          * TBC - tab-clear
3125          * This clears tab-stops. If @args[0] is 0, the tab-stop at the current
3126          * cursor position is cleared. If it is 3, all tab stops are cleared.
3127          *
3128          * Defaults:
3129          *   args[0]: 0
3130          */
3131
3132         unsigned int mode = 0, pos;
3133
3134         if (seq->args[0] > 0)
3135                 mode = seq->args[0];
3136
3137         switch (mode) {
3138         case 0:
3139                 pos = screen->cursor_x;
3140                 if (screen->page->width > 0)
3141                         screen->tabs[pos / 8] &= ~(1U << (pos % 8));
3142                 break;
3143         case 3:
3144                 if (screen->page->width > 0)
3145                         memset(screen->tabs, 0, (screen->page->width + 7) / 8);
3146                 break;
3147         }
3148
3149         return 0;
3150 }
3151
3152 static int screen_VPA(term_screen *screen, const term_seq *seq) {
3153         /*
3154          * VPA - vertical-line-position-absolute
3155          * VPA causes the active position to be moved to the corresponding
3156          * horizontal position. @args[0] specifies the line to jump to. If an
3157          * attempt is made to move the active position below the last line, then
3158          * the active position stops on the last line. 0 is treated as 1.
3159          *
3160          * Defaults:
3161          *   args[0]: 1
3162          */
3163
3164         unsigned int pos = 1;
3165
3166         if (seq->args[0] > 0)
3167                 pos = seq->args[0];
3168
3169         screen_cursor_clear_wrap(screen);
3170         screen_cursor_set_rel(screen, screen->cursor_x, pos - 1);
3171
3172         return 0;
3173 }
3174
3175 static int screen_VPR(term_screen *screen, const term_seq *seq) {
3176         /*
3177          * VPR - vertical-line-position-relative
3178          * VPR causes the active position to be moved to the corresponding
3179          * horizontal position. @args[0] specifies the number of lines to jump
3180          * down relative to the current cursor position. If an attempt is made
3181          * to move the active position below the last line, the active position
3182          * stops at the last line. 0 is treated as 1.
3183          *
3184          * Defaults:
3185          *   args[0]: 1
3186          */
3187
3188         unsigned int num = 1;
3189
3190         if (seq->args[0] > 0)
3191                 num = seq->args[0];
3192
3193         screen_cursor_clear_wrap(screen);
3194         screen_cursor_down(screen, num, false);
3195
3196         return 0;
3197 }
3198
3199 static int screen_VT(term_screen *screen, const term_seq *seq) {
3200         /*
3201          * VT - vertical-tab
3202          * This causes a vertical jump by one line. Terminals treat it exactly
3203          * the same as LF.
3204          */
3205
3206         return screen_LF(screen, seq);
3207 }
3208
3209 static int screen_XTERM_CLLHP(term_screen *screen, const term_seq *seq) {