chiark / gitweb /
c78b9aa70acf33c1da2761599ba7aa53e47574d0
[elogind.git] / src / libsystemd-terminal / term-internal.h
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 #pragma once
23
24 #include <stdbool.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include "term.h"
28 #include "util.h"
29
30 typedef struct term_char term_char_t;
31 typedef struct term_charbuf term_charbuf_t;
32
33 typedef struct term_cell term_cell;
34 typedef struct term_line term_line;
35
36 typedef struct term_page term_page;
37 typedef struct term_history term_history;
38
39 typedef uint32_t term_charset[96];
40 typedef struct term_state term_state;
41
42 /*
43  * Miscellaneous
44  * Sundry things and external helpers.
45  */
46
47 int mk_wcwidth(wchar_t ucs4);
48 int mk_wcwidth_cjk(wchar_t ucs4);
49 int mk_wcswidth(const wchar_t *str, size_t len);
50 int mk_wcswidth_cjk(const wchar_t *str, size_t len);
51
52 /*
53  * Characters
54  * Each cell in a terminal page contains only a single character. This is
55  * usually a single UCS-4 value. However, Unicode allows combining-characters,
56  * therefore, the number of UCS-4 characters per cell must be unlimited. The
57  * term_char_t object wraps the internal combining char API so it can be
58  * treated as a single object.
59  */
60
61 struct term_char {
62         /* never access this value directly */
63         uint64_t _value;
64 };
65
66 struct term_charbuf {
67         /* 3 bytes + zero-terminator */
68         uint32_t buf[4];
69 };
70
71 #define TERM_CHAR_INIT(_val) ((term_char_t){ ._value = (_val) })
72 #define TERM_CHAR_NULL TERM_CHAR_INIT(0)
73
74 term_char_t term_char_set(term_char_t previous, uint32_t append_ucs4);
75 term_char_t term_char_merge(term_char_t base, uint32_t append_ucs4);
76 term_char_t term_char_dup(term_char_t ch);
77 term_char_t term_char_dup_append(term_char_t base, uint32_t append_ucs4);
78
79 const uint32_t *term_char_resolve(term_char_t ch, size_t *s, term_charbuf_t *b);
80 unsigned int term_char_lookup_width(term_char_t ch);
81
82 /* true if @ch is TERM_CHAR_NULL, otherwise false */
83 static inline bool term_char_is_null(term_char_t ch) {
84         return ch._value == 0;
85 }
86
87 /* true if @ch is dynamically allocated and needs to be freed */
88 static inline bool term_char_is_allocated(term_char_t ch) {
89         return !term_char_is_null(ch) && !(ch._value & 0x1);
90 }
91
92 /* true if (a == b), otherwise false; this is (a == b), NOT (*a == *b) */
93 static inline bool term_char_same(term_char_t a, term_char_t b) {
94         return a._value == b._value;
95 }
96
97 /* true if (*a == *b), otherwise false; this is implied by (a == b) */
98 static inline bool term_char_equal(term_char_t a, term_char_t b) {
99         const uint32_t *sa, *sb;
100         term_charbuf_t ca, cb;
101         size_t na, nb;
102
103         sa = term_char_resolve(a, &na, &ca);
104         sb = term_char_resolve(b, &nb, &cb);
105         return na == nb && !memcmp(sa, sb, sizeof(*sa) * na);
106 }
107
108 /* free @ch in case it is dynamically allocated */
109 static inline term_char_t term_char_free(term_char_t ch) {
110         if (term_char_is_allocated(ch))
111                 term_char_set(ch, 0);
112
113         return TERM_CHAR_NULL;
114 }
115
116 /* gcc _cleanup_ helpers */
117 #define _term_char_free_ _cleanup_(term_char_freep)
118 static inline void term_char_freep(term_char_t *p) {
119         term_char_free(*p);
120 }
121
122 /*
123  * Cells
124  * The term_cell structure respresents a single cell in a terminal page. It
125  * contains the stored character, the age of the cell and all its attributes.
126  */
127
128 struct term_cell {
129         term_char_t ch;         /* stored char or TERM_CHAR_NULL */
130         term_age_t age;         /* cell age or TERM_AGE_NULL */
131         term_attr attr;         /* cell attributes */
132         unsigned int cwidth;    /* cached term_char_lookup_width(cell->ch) */
133 };
134
135 /*
136  * Lines
137  * Instead of storing cells in a 2D array, we store them in an array of
138  * dynamically allocated lines. This way, scrolling can be implemented very
139  * fast without moving any cells at all. Similarly, the scrollback-buffer is
140  * much simpler to implement.
141  * We use term_line to store a single line. It contains an array of cells, a
142  * fill-state which remembers the amount of blanks on the right side, a
143  * separate age just for the line which can overwrite the age for all cells,
144  * and some management data.
145  */
146
147 struct term_line {
148         term_line *lines_next;          /* linked-list for histories */
149         term_line *lines_prev;          /* linked-list for histories */
150
151         unsigned int width;             /* visible width of line */
152         unsigned int n_cells;           /* # of allocated cells */
153         term_cell *cells;               /* cell-array */
154
155         term_age_t age;                 /* line age */
156         unsigned int fill;              /* # of valid cells; starting left */
157 };
158
159 int term_line_new(term_line **out);
160 term_line *term_line_free(term_line *line);
161
162 #define _term_line_free_ _cleanup_(term_line_freep)
163 DEFINE_TRIVIAL_CLEANUP_FUNC(term_line*, term_line_free);
164
165 int term_line_reserve(term_line *line, unsigned int width, const term_attr *attr, term_age_t age, unsigned int protect_width);
166 void term_line_set_width(term_line *line, unsigned int width);
167 void term_line_write(term_line *line, unsigned int pos_x, term_char_t ch, unsigned int cwidth, const term_attr *attr, term_age_t age, bool insert_mode);
168 void term_line_insert(term_line *line, unsigned int from, unsigned int num, const term_attr *attr, term_age_t age);
169 void term_line_delete(term_line *line, unsigned int from, unsigned int num, const term_attr *attr, term_age_t age);
170 void term_line_append_combchar(term_line *line, unsigned int pos_x, uint32_t ucs4, term_age_t age);
171 void term_line_erase(term_line *line, unsigned int from, unsigned int num, const term_attr *attr, term_age_t age, bool keep_protected);
172 void term_line_reset(term_line *line, const term_attr *attr, term_age_t age);
173
174 void term_line_link(term_line *line, term_line **first, term_line **last);
175 void term_line_link_tail(term_line *line, term_line **first, term_line **last);
176 void term_line_unlink(term_line *line, term_line **first, term_line **last);
177
178 #define TERM_LINE_LINK(_line, _head) term_line_link((_line), &(_head)->lines_first, &(_head)->lines_last)
179 #define TERM_LINE_LINK_TAIL(_line, _head) term_line_link_tail((_line), &(_head)->lines_first, &(_head)->lines_last)
180 #define TERM_LINE_UNLINK(_line, _head) term_line_unlink((_line), &(_head)->lines_first, &(_head)->lines_last)
181
182 /*
183  * Pages
184  * A page represents the 2D table containing all cells of a terminal. It stores
185  * lines as an array of pointers so scrolling becomes a simple line-shuffle
186  * operation.
187  * Scrolling is always targeted only at the scroll-region defined via scroll_idx
188  * and scroll_num. The fill-state keeps track of the number of touched lines in
189  * the scroll-region. @width and @height describe the visible region of the page
190  * and are guaranteed to be allocated at all times.
191  */
192
193 struct term_page {
194         term_age_t age;                 /* page age */
195
196         term_line **lines;              /* array of line-pointers */
197         term_line **line_cache;         /* cache for temporary operations */
198         unsigned int n_lines;           /* # of allocated lines */
199
200         unsigned int width;             /* width of visible area */
201         unsigned int height;            /* height of visible area */
202         unsigned int scroll_idx;        /* scrolling-region start index */
203         unsigned int scroll_num;        /* scrolling-region length in lines */
204         unsigned int scroll_fill;       /* # of valid scroll-lines */
205 };
206
207 int term_page_new(term_page **out);
208 term_page *term_page_free(term_page *page);
209
210 #define _term_page_free_ _cleanup_(term_page_freep)
211 DEFINE_TRIVIAL_CLEANUP_FUNC(term_page*, term_page_free);
212
213 term_cell *term_page_get_cell(term_page *page, unsigned int x, unsigned int y);
214
215 int term_page_reserve(term_page *page, unsigned int cols, unsigned int rows, const term_attr *attr, term_age_t age);
216 void term_page_resize(term_page *page, unsigned int cols, unsigned int rows, const term_attr *attr, term_age_t age, term_history *history);
217 void term_page_write(term_page *page, unsigned int pos_x, unsigned int pos_y, term_char_t ch, unsigned int cwidth, const term_attr *attr, term_age_t age, bool insert_mode);
218 void term_page_insert_cells(term_page *page, unsigned int from_x, unsigned int from_y, unsigned int num, const term_attr *attr, term_age_t age);
219 void term_page_delete_cells(term_page *page, unsigned int from_x, unsigned int from_y, unsigned int num, const term_attr *attr, term_age_t age);
220 void term_page_append_combchar(term_page *page, unsigned int pos_x, unsigned int pos_y, uint32_t ucs4, term_age_t age);
221 void term_page_erase(term_page *page, unsigned int from_x, unsigned int from_y, unsigned int to_x, unsigned int to_y, const term_attr *attr, term_age_t age, bool keep_protected);
222 void term_page_reset(term_page *page, const term_attr *attr, term_age_t age);
223
224 void term_page_set_scroll_region(term_page *page, unsigned int idx, unsigned int num);
225 void term_page_scroll_up(term_page *page, unsigned int num, const term_attr *attr, term_age_t age, term_history *history);
226 void term_page_scroll_down(term_page *page, unsigned int num, const term_attr *attr, term_age_t age, term_history *history);
227 void term_page_insert_lines(term_page *page, unsigned int pos_y, unsigned int num, const term_attr *attr, term_age_t age);
228 void term_page_delete_lines(term_page *page, unsigned int pos_y, unsigned int num, const term_attr *attr, term_age_t age);
229
230 /*
231  * Histories
232  * Scroll-back buffers use term_history objects to store scroll-back lines. A
233  * page is independent of the history used. All page operations that modify a
234  * history take it as separate argument. You're free to pass NULL at all times
235  * if no history should be used.
236  * Lines are stored in a linked list as no complex operations are ever done on
237  * history lines, besides pushing/poping. Note that history lines do not have a
238  * guaranteed minimum length. Any kind of line might be stored there. Missing
239  * cells should be cleared to the background color.
240  */
241
242 struct term_history {
243         term_line *lines_first;
244         term_line *lines_last;
245         unsigned int n_lines;
246         unsigned int max_lines;
247 };
248
249 int term_history_new(term_history **out);
250 term_history *term_history_free(term_history *history);
251
252 #define _term_history_free_ _cleanup_(term_history_freep)
253 DEFINE_TRIVIAL_CLEANUP_FUNC(term_history*, term_history_free);
254
255 void term_history_clear(term_history *history);
256 void term_history_trim(term_history *history, unsigned int max);
257 void term_history_push(term_history *history, term_line *line);
258 term_line *term_history_pop(term_history *history, unsigned int reserve_width, const term_attr *attr, term_age_t age);
259 unsigned int term_history_peek(term_history *history, unsigned int max, unsigned int reserve_width, const term_attr *attr, term_age_t age);
260
261 /*
262  * Parsers
263  * The term_parser object parses control-sequences for both host and terminal
264  * side. Based on this parser, there is a set of command-parsers that take a
265  * term_seq sequence and returns the command it represents. This is different
266  * for host and terminal side so a different set of parsers is provided.
267  */
268
269 enum {
270         TERM_SEQ_NONE,                  /* placeholder, no sequence parsed */
271
272         TERM_SEQ_IGNORE,                /* no-op character */
273         TERM_SEQ_GRAPHIC,               /* graphic character */
274         TERM_SEQ_CONTROL,               /* control character */
275         TERM_SEQ_ESCAPE,                /* escape sequence */
276         TERM_SEQ_CSI,                   /* control sequence function */
277         TERM_SEQ_DCS,                   /* device control string */
278         TERM_SEQ_OSC,                   /* operating system control */
279
280         TERM_SEQ_CNT
281 };
282
283 enum {
284         /* these must be kept compatible to (1U << (ch - 0x20)) */
285
286         TERM_SEQ_FLAG_SPACE             = (1U <<  0),   /* char:   */
287         TERM_SEQ_FLAG_BANG              = (1U <<  1),   /* char: ! */
288         TERM_SEQ_FLAG_DQUOTE            = (1U <<  2),   /* char: " */
289         TERM_SEQ_FLAG_HASH              = (1U <<  3),   /* char: # */
290         TERM_SEQ_FLAG_CASH              = (1U <<  4),   /* char: $ */
291         TERM_SEQ_FLAG_PERCENT           = (1U <<  5),   /* char: % */
292         TERM_SEQ_FLAG_AND               = (1U <<  6),   /* char: & */
293         TERM_SEQ_FLAG_SQUOTE            = (1U <<  7),   /* char: ' */
294         TERM_SEQ_FLAG_POPEN             = (1U <<  8),   /* char: ( */
295         TERM_SEQ_FLAG_PCLOSE            = (1U <<  9),   /* char: ) */
296         TERM_SEQ_FLAG_MULT              = (1U << 10),   /* char: * */
297         TERM_SEQ_FLAG_PLUS              = (1U << 11),   /* char: + */
298         TERM_SEQ_FLAG_COMMA             = (1U << 12),   /* char: , */
299         TERM_SEQ_FLAG_MINUS             = (1U << 13),   /* char: - */
300         TERM_SEQ_FLAG_DOT               = (1U << 14),   /* char: . */
301         TERM_SEQ_FLAG_SLASH             = (1U << 15),   /* char: / */
302
303         /* 16-35 is reserved for numbers; unused */
304
305         /* COLON is reserved            = (1U << 26),      char: : */
306         /* SEMICOLON is reserved        = (1U << 27),      char: ; */
307         TERM_SEQ_FLAG_LT                = (1U << 28),   /* char: < */
308         TERM_SEQ_FLAG_EQUAL             = (1U << 29),   /* char: = */
309         TERM_SEQ_FLAG_GT                = (1U << 30),   /* char: > */
310         TERM_SEQ_FLAG_WHAT              = (1U << 31),   /* char: ? */
311 };
312
313 enum {
314         TERM_CMD_NONE,                          /* placeholder */
315         TERM_CMD_GRAPHIC,                       /* graphics character */
316
317         TERM_CMD_BEL,                           /* bell */
318         TERM_CMD_BS,                            /* backspace */
319         TERM_CMD_CBT,                           /* cursor-backward-tabulation */
320         TERM_CMD_CHA,                           /* cursor-horizontal-absolute */
321         TERM_CMD_CHT,                           /* cursor-horizontal-forward-tabulation */
322         TERM_CMD_CNL,                           /* cursor-next-line */
323         TERM_CMD_CPL,                           /* cursor-previous-line */
324         TERM_CMD_CR,                            /* carriage-return */
325         TERM_CMD_CUB,                           /* cursor-backward */
326         TERM_CMD_CUD,                           /* cursor-down */
327         TERM_CMD_CUF,                           /* cursor-forward */
328         TERM_CMD_CUP,                           /* cursor-position */
329         TERM_CMD_CUU,                           /* cursor-up */
330         TERM_CMD_DA1,                           /* primary-device-attributes */
331         TERM_CMD_DA2,                           /* secondary-device-attributes */
332         TERM_CMD_DA3,                           /* tertiary-device-attributes */
333         TERM_CMD_DC1,                           /* device-control-1 or XON */
334         TERM_CMD_DC3,                           /* device-control-3 or XOFF */
335         TERM_CMD_DCH,                           /* delete-character */
336         TERM_CMD_DECALN,                        /* screen-alignment-pattern */
337         TERM_CMD_DECANM,                        /* ansi-mode */
338         TERM_CMD_DECBI,                         /* back-index */
339         TERM_CMD_DECCARA,                       /* change-attributes-in-rectangular-area */
340         TERM_CMD_DECCRA,                        /* copy-rectangular-area */
341         TERM_CMD_DECDC,                         /* delete-column */
342         TERM_CMD_DECDHL_BH,                     /* double-width-double-height-line: bottom half */
343         TERM_CMD_DECDHL_TH,                     /* double-width-double-height-line: top half */
344         TERM_CMD_DECDWL,                        /* double-width-single-height-line */
345         TERM_CMD_DECEFR,                        /* enable-filter-rectangle */
346         TERM_CMD_DECELF,                        /* enable-local-functions */
347         TERM_CMD_DECELR,                        /* enable-locator-reporting */
348         TERM_CMD_DECERA,                        /* erase-rectangular-area */
349         TERM_CMD_DECFI,                         /* forward-index */
350         TERM_CMD_DECFRA,                        /* fill-rectangular-area */
351         TERM_CMD_DECIC,                         /* insert-column */
352         TERM_CMD_DECID,                         /* return-terminal-id */
353         TERM_CMD_DECINVM,                       /* invoke-macro */
354         TERM_CMD_DECKBD,                        /* keyboard-language-selection */
355         TERM_CMD_DECKPAM,                       /* keypad-application-mode */
356         TERM_CMD_DECKPNM,                       /* keypad-numeric-mode */
357         TERM_CMD_DECLFKC,                       /* local-function-key-control */
358         TERM_CMD_DECLL,                         /* load-leds */
359         TERM_CMD_DECLTOD,                       /* load-time-of-day */
360         TERM_CMD_DECPCTERM,                     /* pcterm-mode */
361         TERM_CMD_DECPKA,                        /* program-key-action */
362         TERM_CMD_DECPKFMR,                      /* program-key-free-memory-report */
363         TERM_CMD_DECRARA,                       /* reverse-attributes-in-rectangular-area */
364         TERM_CMD_DECRC,                         /* restore-cursor */
365         TERM_CMD_DECREQTPARM,                   /* request-terminal-parameters */
366         TERM_CMD_DECRPKT,                       /* report-key-type */
367         TERM_CMD_DECRQCRA,                      /* request-checksum-of-rectangular-area */
368         TERM_CMD_DECRQDE,                       /* request-display-extent */
369         TERM_CMD_DECRQKT,                       /* request-key-type */
370         TERM_CMD_DECRQLP,                       /* request-locator-position */
371         TERM_CMD_DECRQM_ANSI,                   /* request-mode-ansi */
372         TERM_CMD_DECRQM_DEC,                    /* request-mode-dec */
373         TERM_CMD_DECRQPKFM,                     /* request-program-key-free-memory */
374         TERM_CMD_DECRQPSR,                      /* request-presentation-state-report */
375         TERM_CMD_DECRQTSR,                      /* request-terminal-state-report */
376         TERM_CMD_DECRQUPSS,                     /* request-user-preferred-supplemental-set */
377         TERM_CMD_DECSACE,                       /* select-attribute-change-extent */
378         TERM_CMD_DECSASD,                       /* select-active-status-display */
379         TERM_CMD_DECSC,                         /* save-cursor */
380         TERM_CMD_DECSCA,                        /* select-character-protection-attribute */
381         TERM_CMD_DECSCL,                        /* select-conformance-level */
382         TERM_CMD_DECSCP,                        /* select-communication-port */
383         TERM_CMD_DECSCPP,                       /* select-columns-per-page */
384         TERM_CMD_DECSCS,                        /* select-communication-speed */
385         TERM_CMD_DECSCUSR,                      /* set-cursor-style */
386         TERM_CMD_DECSDDT,                       /* select-disconnect-delay-time */
387         TERM_CMD_DECSDPT,                       /* select-digital-printed-data-type */
388         TERM_CMD_DECSED,                        /* selective-erase-in-display */
389         TERM_CMD_DECSEL,                        /* selective-erase-in-line */
390         TERM_CMD_DECSERA,                       /* selective-erase-rectangular-area */
391         TERM_CMD_DECSFC,                        /* select-flow-control */
392         TERM_CMD_DECSKCV,                       /* set-key-click-volume */
393         TERM_CMD_DECSLCK,                       /* set-lock-key-style */
394         TERM_CMD_DECSLE,                        /* select-locator-events */
395         TERM_CMD_DECSLPP,                       /* set-lines-per-page */
396         TERM_CMD_DECSLRM_OR_SC,                 /* set-left-and-right-margins or save-cursor */
397         TERM_CMD_DECSMBV,                       /* set-margin-bell-volume */
398         TERM_CMD_DECSMKR,                       /* select-modifier-key-reporting */
399         TERM_CMD_DECSNLS,                       /* set-lines-per-screen */
400         TERM_CMD_DECSPP,                        /* set-port-parameter */
401         TERM_CMD_DECSPPCS,                      /* select-pro-printer-character-set */
402         TERM_CMD_DECSPRTT,                      /* select-printer-type */
403         TERM_CMD_DECSR,                         /* secure-reset */
404         TERM_CMD_DECSRFR,                       /* select-refresh-rate */
405         TERM_CMD_DECSSCLS,                      /* set-scroll-speed */
406         TERM_CMD_DECSSDT,                       /* select-status-display-line-type */
407         TERM_CMD_DECSSL,                        /* select-setup-language */
408         TERM_CMD_DECST8C,                       /* set-tab-at-every-8-columns */
409         TERM_CMD_DECSTBM,                       /* set-top-and-bottom-margins */
410         TERM_CMD_DECSTR,                        /* soft-terminal-reset */
411         TERM_CMD_DECSTRL,                       /* set-transmit-rate-limit */
412         TERM_CMD_DECSWBV,                       /* set-warning-bell-volume */
413         TERM_CMD_DECSWL,                        /* single-width-single-height-line */
414         TERM_CMD_DECTID,                        /* select-terminal-id */
415         TERM_CMD_DECTME,                        /* terminal-mode-emulation */
416         TERM_CMD_DECTST,                        /* invoke-confidence-test */
417         TERM_CMD_DL,                            /* delete-line */
418         TERM_CMD_DSR_ANSI,                      /* device-status-report-ansi */
419         TERM_CMD_DSR_DEC,                       /* device-status-report-dec */
420         TERM_CMD_ECH,                           /* erase-character */
421         TERM_CMD_ED,                            /* erase-in-display */
422         TERM_CMD_EL,                            /* erase-in-line */
423         TERM_CMD_ENQ,                           /* enquiry */
424         TERM_CMD_EPA,                           /* end-of-guarded-area */
425         TERM_CMD_FF,                            /* form-feed */
426         TERM_CMD_HPA,                           /* horizontal-position-absolute */
427         TERM_CMD_HPR,                           /* horizontal-position-relative */
428         TERM_CMD_HT,                            /* horizontal-tab */
429         TERM_CMD_HTS,                           /* horizontal-tab-set */
430         TERM_CMD_HVP,                           /* horizontal-and-vertical-position */
431         TERM_CMD_ICH,                           /* insert-character */
432         TERM_CMD_IL,                            /* insert-line */
433         TERM_CMD_IND,                           /* index */
434         TERM_CMD_LF,                            /* line-feed */
435         TERM_CMD_LS1R,                          /* locking-shift-1-right */
436         TERM_CMD_LS2,                           /* locking-shift-2 */
437         TERM_CMD_LS2R,                          /* locking-shift-2-right */
438         TERM_CMD_LS3,                           /* locking-shift-3 */
439         TERM_CMD_LS3R,                          /* locking-shift-3-right */
440         TERM_CMD_MC_ANSI,                       /* media-copy-ansi */
441         TERM_CMD_MC_DEC,                        /* media-copy-dec */
442         TERM_CMD_NEL,                           /* next-line */
443         TERM_CMD_NP,                            /* next-page */
444         TERM_CMD_NULL,                          /* null */
445         TERM_CMD_PP,                            /* preceding-page */
446         TERM_CMD_PPA,                           /* page-position-absolute */
447         TERM_CMD_PPB,                           /* page-position-backward */
448         TERM_CMD_PPR,                           /* page-position-relative */
449         TERM_CMD_RC,                            /* restore-cursor */
450         TERM_CMD_REP,                           /* repeat */
451         TERM_CMD_RI,                            /* reverse-index */
452         TERM_CMD_RIS,                           /* reset-to-initial-state */
453         TERM_CMD_RM_ANSI,                       /* reset-mode-ansi */
454         TERM_CMD_RM_DEC,                        /* reset-mode-dec */
455         TERM_CMD_S7C1T,                         /* set-7bit-c1-terminal */
456         TERM_CMD_S8C1T,                         /* set-8bit-c1-terminal */
457         TERM_CMD_SCS,                           /* select-character-set */
458         TERM_CMD_SD,                            /* scroll-down */
459         TERM_CMD_SGR,                           /* select-graphics-rendition */
460         TERM_CMD_SI,                            /* shift-in */
461         TERM_CMD_SM_ANSI,                       /* set-mode-ansi */
462         TERM_CMD_SM_DEC,                        /* set-mode-dec */
463         TERM_CMD_SO,                            /* shift-out */
464         TERM_CMD_SPA,                           /* start-of-protected-area */
465         TERM_CMD_SS2,                           /* single-shift-2 */
466         TERM_CMD_SS3,                           /* single-shift-3 */
467         TERM_CMD_ST,                            /* string-terminator */
468         TERM_CMD_SU,                            /* scroll-up */
469         TERM_CMD_SUB,                           /* substitute */
470         TERM_CMD_TBC,                           /* tab-clear */
471         TERM_CMD_VPA,                           /* vertical-line-position-absolute */
472         TERM_CMD_VPR,                           /* vertical-line-position-relative */
473         TERM_CMD_VT,                            /* vertical-tab */
474         TERM_CMD_XTERM_CLLHP,                   /* xterm-cursor-lower-left-hp-bugfix */
475         TERM_CMD_XTERM_IHMT,                    /* xterm-initiate-highlight-mouse-tracking*/
476         TERM_CMD_XTERM_MLHP,                    /* xterm-memory-lock-hp-bugfix */
477         TERM_CMD_XTERM_MUHP,                    /* xterm-memory-unlock-hp-bugfix */
478         TERM_CMD_XTERM_RPM,                     /* xterm-restore-private-mode */
479         TERM_CMD_XTERM_RRV,                     /* xterm-reset-resource-value */
480         TERM_CMD_XTERM_RTM,                     /* xterm-reset-title-mode */
481         TERM_CMD_XTERM_SACL1,                   /* xterm-set-ansi-conformance-level-1 */
482         TERM_CMD_XTERM_SACL2,                   /* xterm-set-ansi-conformance-level-2 */
483         TERM_CMD_XTERM_SACL3,                   /* xterm-set-ansi-conformance-level-3 */
484         TERM_CMD_XTERM_SDCS,                    /* xterm-set-default-character-set */
485         TERM_CMD_XTERM_SGFX,                    /* xterm-sixel-graphics */
486         TERM_CMD_XTERM_SPM,                     /* xterm-set-private-mode */
487         TERM_CMD_XTERM_SRV,                     /* xterm-set-resource-value */
488         TERM_CMD_XTERM_STM,                     /* xterm-set-title-mode */
489         TERM_CMD_XTERM_SUCS,                    /* xterm-set-utf8-character-set */
490         TERM_CMD_XTERM_WM,                      /* xterm-window-management */
491
492         TERM_CMD_CNT
493 };
494
495 enum {
496         /*
497          * Charsets: DEC marks charsets according to "Digital Equ. Corp.".
498          *           NRCS marks charsets according to the "National Replacement
499          *           Character Sets". ISO marks charsets according to ISO-8859.
500          * The USERDEF charset is special and can be modified by the host.
501          */
502
503         TERM_CHARSET_NONE,
504
505         /* 96-compat charsets */
506         TERM_CHARSET_ISO_LATIN1_SUPPLEMENTAL,
507         TERM_CHARSET_BRITISH_NRCS = TERM_CHARSET_ISO_LATIN1_SUPPLEMENTAL,
508         TERM_CHARSET_ISO_LATIN2_SUPPLEMENTAL,
509         TERM_CHARSET_AMERICAN_NRCS = TERM_CHARSET_ISO_LATIN2_SUPPLEMENTAL,
510         TERM_CHARSET_ISO_LATIN5_SUPPLEMENTAL,
511         TERM_CHARSET_ISO_GREEK_SUPPLEMENTAL,
512         TERM_CHARSET_ISO_HEBREW_SUPPLEMENTAL,
513         TERM_CHARSET_ISO_LATIN_CYRILLIC,
514
515         TERM_CHARSET_96_CNT,
516
517         /* 94-compat charsets */
518         TERM_CHARSET_DEC_SPECIAL_GRAPHIC = TERM_CHARSET_96_CNT,
519         TERM_CHARSET_DEC_SUPPLEMENTAL,
520         TERM_CHARSET_DEC_TECHNICAL,
521         TERM_CHARSET_CYRILLIC_DEC,
522         TERM_CHARSET_DUTCH_NRCS,
523         TERM_CHARSET_FINNISH_NRCS,
524         TERM_CHARSET_FRENCH_NRCS,
525         TERM_CHARSET_FRENCH_CANADIAN_NRCS,
526         TERM_CHARSET_GERMAN_NRCS,
527         TERM_CHARSET_GREEK_DEC,
528         TERM_CHARSET_GREEK_NRCS,
529         TERM_CHARSET_HEBREW_DEC,
530         TERM_CHARSET_HEBREW_NRCS,
531         TERM_CHARSET_ITALIAN_NRCS,
532         TERM_CHARSET_NORWEGIAN_DANISH_NRCS,
533         TERM_CHARSET_PORTUGUESE_NRCS,
534         TERM_CHARSET_RUSSIAN_NRCS,
535         TERM_CHARSET_SCS_NRCS,
536         TERM_CHARSET_SPANISH_NRCS,
537         TERM_CHARSET_SWEDISH_NRCS,
538         TERM_CHARSET_SWISS_NRCS,
539         TERM_CHARSET_TURKISH_DEC,
540         TERM_CHARSET_TURKISH_NRCS,
541
542         TERM_CHARSET_94_CNT,
543
544         /* special charsets */
545         TERM_CHARSET_USERPREF_SUPPLEMENTAL = TERM_CHARSET_94_CNT,
546
547         TERM_CHARSET_CNT,
548 };
549
550 extern term_charset term_unicode_lower;
551 extern term_charset term_unicode_upper;
552 extern term_charset term_dec_supplemental_graphics;
553 extern term_charset term_dec_special_graphics;
554
555 #define TERM_PARSER_ARG_MAX (16)
556 #define TERM_PARSER_ST_MAX (4096)
557
558 struct term_seq {
559         unsigned int type;
560         unsigned int command;
561         uint32_t terminator;
562         unsigned int intermediates;
563         unsigned int charset;
564         unsigned int n_args;
565         int args[TERM_PARSER_ARG_MAX];
566         unsigned int n_st;
567         char *st;
568 };
569
570 struct term_parser {
571         term_seq seq;
572         size_t st_alloc;
573         unsigned int state;
574
575         bool is_host : 1;
576 };
577
578 /*
579  * Screens
580  * A term_screen object represents the terminal-side of the communication. It
581  * connects the term-parser and term-pages and handles all required commands.
582  * All state is managed by it.
583  */
584
585 enum {
586         TERM_FLAG_7BIT_MODE                     = (1U << 0),    /* 7bit mode (default: on) */
587         TERM_FLAG_HIDE_CURSOR                   = (1U << 1),    /* hide cursor caret (default: off) */
588         TERM_FLAG_INHIBIT_TPARM                 = (1U << 2),    /* do not send TPARM unrequested (default: off) */
589         TERM_FLAG_NEWLINE_MODE                  = (1U << 3),    /* perform carriage-return on line-feeds (default: off) */
590         TERM_FLAG_PENDING_WRAP                  = (1U << 4),    /* wrap-around is pending */
591         TERM_FLAG_KEYPAD_MODE                   = (1U << 5),    /* application-keypad mode (default: off) */
592         TERM_FLAG_CURSOR_KEYS                   = (1U << 6),    /* enable application cursor-keys (default: off) */
593 };
594
595 enum {
596         TERM_CONFORMANCE_LEVEL_VT52,
597         TERM_CONFORMANCE_LEVEL_VT100,
598         TERM_CONFORMANCE_LEVEL_VT400,
599         TERM_CONFORMANCE_LEVEL_CNT,
600 };
601
602 struct term_state {
603         unsigned int cursor_x;
604         unsigned int cursor_y;
605         term_attr attr;
606         term_charset **gl;
607         term_charset **gr;
608         term_charset **glt;
609         term_charset **grt;
610
611         bool auto_wrap : 1;
612         bool origin_mode : 1;
613 };
614
615 struct term_screen {
616         unsigned long ref;
617         term_age_t age;
618
619         term_page *page;
620         term_page *page_main;
621         term_page *page_alt;
622         term_history *history;
623         term_history *history_main;
624
625         unsigned int n_tabs;
626         uint8_t *tabs;
627
628         term_utf8 utf8;
629         term_parser *parser;
630
631         term_screen_write_fn write_fn;
632         void *write_fn_data;
633         term_screen_cmd_fn cmd_fn;
634         void *cmd_fn_data;
635
636         unsigned int flags;
637         unsigned int conformance_level;
638         term_attr default_attr;
639
640         term_charset *g0;
641         term_charset *g1;
642         term_charset *g2;
643         term_charset *g3;
644
645         char *answerback;
646
647         term_state state;
648         term_state saved;
649 };