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