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