1 /*
2  * libtsm - VT Emulator
3  *
4  * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com>
5  * Copyright (c) 2015-2018 Bjorn Stahl <contact@arcan-fe.com>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files
9  * (the "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26 
27 /*
28  * Virtual Terminal Emulator
29  * This is the VT implementation. It is written from scratch. It uses the
30  * screen state-machine as output and is tightly bound to it. It supports
31  * functionality from vt100 up to vt500 series. It doesn't implement an
32  * explicitly selected terminal but tries to support the most important commands
33  * to be compatible with existing implementations. However, full vt102
34  * compatibility is the least that is provided.
35  *
36  * The main parser in this file controls the parser-state and dispatches the
37  * actions to the related handlers. The parser is based on the state-diagram
38  * from Paul Williams: http://vt100.net/emu/
39  * It is written from scratch, though.
40  * This parser is fully compatible up to the vt500 series. It requires UTF-8 and
41  * does not support any other input encoding. The G0 and G1 sets are therefore
42  * defined as subsets of UTF-8. You may still map G0-G3 into GL, though.
43  *
44  * However, the CSI/DCS/etc handlers are not designed after a specific VT
45  * series. We try to support all vt102 commands but implement several other
46  * often used sequences, too. Feel free to add further.
47  */
48 
49 #include <errno.h>
50 #include <stdarg.h>
51 #include <inttypes.h>
52 #include "libtsm_int.h"
53 
54 /* Input parser states */
55 enum parser_state {
56 	STATE_NONE,		/* placeholder */
57 	STATE_GROUND,		/* initial state and ground */
58 	STATE_ESC,		/* ESC sequence was started */
59 	STATE_ESC_INT,		/* intermediate escape characters */
60 	STATE_CSI_ENTRY,	/* starting CSI sequence */
61 	STATE_CSI_PARAM,	/* CSI parameters */
62 	STATE_CSI_INT,		/* intermediate CSI characters */
63 	STATE_CSI_IGNORE,	/* CSI error; ignore this CSI sequence */
64 	STATE_DCS_ENTRY,	/* starting DCS sequence */
65 	STATE_DCS_PARAM,	/* DCS parameters */
66 	STATE_DCS_INT,		/* intermediate DCS characters */
67 	STATE_DCS_PASS,		/* DCS data passthrough */
68 	STATE_DCS_IGNORE,	/* DCS error; ignore this DCS sequence */
69 	STATE_OSC_STRING,	/* parsing OCS sequence */
70 	STATE_ST_IGNORE,	/* unimplemented seq; ignore until ST */
71 	STATE_NUM
72 };
73 
74 /* Input parser actions */
75 enum parser_action {
76 	ACTION_NONE = 0, /* placeholder */
77 	ACTION_IGNORE,		/* ignore the character entirely */
78 	ACTION_PRINT,		/* print the character on the console */
79 	ACTION_EXECUTE,		/* execute single control character (C0/C1) */
80 	ACTION_CLEAR,		/* clear current parameter state */
81 	ACTION_COLLECT,		/* collect intermediate character */
82 	ACTION_PARAM,		/* collect parameter character */
83 	ACTION_ESC_DISPATCH,	/* dispatch escape sequence */
84 	ACTION_CSI_DISPATCH,	/* dispatch csi sequence */
85 	ACTION_DCS_START,	/* start of DCS data */
86 	ACTION_DCS_COLLECT,	/* collect DCS data */
87 	ACTION_DCS_END,		/* end of DCS data */
88 	ACTION_OSC_START,	/* start of OSC data */
89 	ACTION_OSC_COLLECT,	/* collect OSC data */
90 	ACTION_OSC_END,		/* end of OSC data */
91 };
92 
93 static const char* action_lut[] = {
94 	"none",
95 	"ignore",
96 	"print",
97 	"execute",
98 	"clear",
99 	"collect",
100 	"param",
101 	"esc",
102 	"csi",
103 	"dcs_s",
104 	"dcs_c",
105 	"dcs_e",
106 	"osc_s",
107 	"osc_c",
108 	"osc_e",
109 };
110 
111 const static int MOUSE_PROTO = MOUSE_SGR | MOUSE_X10 | MOUSE_RXVT;
112 
113 /* CSI flags */
114 #define CSI_BANG	0x0001		/* CSI: ! */
115 #define CSI_CASH	0x0002		/* CSI: $ */
116 #define CSI_WHAT	0x0004		/* CSI: ? */
117 #define CSI_GT		0x0008		/* CSI: > */
118 #define CSI_SPACE	0x0010		/* CSI:   */
119 #define CSI_SQUOTE	0x0020		/* CSI: ' */
120 #define CSI_DQUOTE	0x0040		/* CSI: " */
121 #define CSI_MULT	0x0080		/* CSI: * */
122 #define CSI_PLUS	0x0100		/* CSI: + */
123 #define CSI_POPEN	0x0200		/* CSI: ( */
124 #define CSI_PCLOSE	0x0400		/* CSI: ) */
125 
126 /* terminal flags */
127 #define FLAG_CURSOR_KEY_MODE			0x00000001 /* DEC cursor key mode */
128 #define FLAG_KEYPAD_APPLICATION_MODE		0x00000002 /* DEC keypad application mode; TODO: toggle on numlock? */
129 #define FLAG_LINE_FEED_NEW_LINE_MODE		0x00000004 /* DEC line-feed/new-line mode */
130 #define FLAG_8BIT_MODE				0x00000008 /* Disable UTF-8 mode and enable 8bit compatible mode */
131 #define FLAG_7BIT_MODE				0x00000010 /* Disable 8bit mode and use 7bit compatible mode */
132 #define FLAG_USE_C1				0x00000020 /* Explicitly use 8bit C1 codes; TODO: implement */
133 #define FLAG_KEYBOARD_ACTION_MODE		0x00000040 /* Disable keyboard; TODO: implement? */
134 #define FLAG_INSERT_REPLACE_MODE		0x00000080 /* Enable insert mode */
135 #define FLAG_SEND_RECEIVE_MODE			0x00000100 /* Disable local echo */
136 #define FLAG_TEXT_CURSOR_MODE			0x00000200 /* Show cursor */
137 #define FLAG_INVERSE_SCREEN_MODE		0x00000400 /* Inverse colors */
138 #define FLAG_ORIGIN_MODE			0x00000800 /* Relative origin for cursor */
139 #define FLAG_AUTO_WRAP_MODE			0x00001000 /* Auto line wrap mode */
140 #define FLAG_AUTO_REPEAT_MODE			0x00002000 /* Auto repeat key press; TODO: implement */
141 #define FLAG_NATIONAL_CHARSET_MODE		0x00004000 /* Send keys from nation charsets; TODO: implement */
142 #define FLAG_BACKGROUND_COLOR_ERASE_MODE	0x00008000 /* Set background color on erase (bce) */
143 #define FLAG_PREPEND_ESCAPE			0x00010000 /* Prepend escape character to next output */
144 #define FLAG_TITE_INHIBIT_MODE			0x00020000 /* Prevent switching to alternate screen buffer */
145 #define FLAG_PASTE_BRACKET 0x00040000 /* Bracketed Paste mode */
146 
147 static uint8_t color_palette[VTE_COLOR_NUM][3] = {
148 	[VTE_COLOR_BLACK]         = {   0,   0,   0 },
149 	[VTE_COLOR_RED]           = { 205,   0,   0 },
150 	[VTE_COLOR_GREEN]         = {   0, 205,   0 },
151 	[VTE_COLOR_YELLOW]        = { 205, 205,   0 },
152 	[VTE_COLOR_BLUE]          = {   0,   0, 238 },
153 	[VTE_COLOR_MAGENTA]       = { 205,   0, 205 },
154 	[VTE_COLOR_CYAN]          = {   0, 205, 205 },
155 	[VTE_COLOR_LIGHT_GREY]    = { 229, 229, 229 },
156 	[VTE_COLOR_DARK_GREY]     = { 127, 127, 127 },
157 	[VTE_COLOR_LIGHT_RED]     = { 255,   0,   0 },
158 	[VTE_COLOR_LIGHT_GREEN]   = {   0, 255,   0 },
159 	[VTE_COLOR_LIGHT_YELLOW]  = { 255, 255,   0 },
160 	[VTE_COLOR_LIGHT_BLUE]    = {  92,  92, 255 },
161 	[VTE_COLOR_LIGHT_MAGENTA] = { 255,   0, 255 },
162 	[VTE_COLOR_LIGHT_CYAN]    = {   0, 255, 255 },
163 	[VTE_COLOR_WHITE]         = { 255, 255, 255 },
164 
165 	[VTE_COLOR_FOREGROUND]    = { 229, 229, 229 },
166 	[VTE_COLOR_BACKGROUND]    = {   0,   0,   0 },
167 };
168 
169 static uint8_t color_palette_solarized[VTE_COLOR_NUM][3] = {
170 	[VTE_COLOR_BLACK]         = {   7,  54,  66 },
171 	[VTE_COLOR_RED]           = { 220,  50,  47 },
172 	[VTE_COLOR_GREEN]         = { 133, 153,   0 },
173 	[VTE_COLOR_YELLOW]        = { 181, 137,   0 },
174 	[VTE_COLOR_BLUE]          = {  38, 139, 210 },
175 	[VTE_COLOR_MAGENTA]       = { 211,  54, 130 },
176 	[VTE_COLOR_CYAN]          = {  42, 161, 152 },
177 	[VTE_COLOR_LIGHT_GREY]    = { 238, 232, 213 },
178 	[VTE_COLOR_DARK_GREY]     = {   0,  43,  54 },
179 	[VTE_COLOR_LIGHT_RED]     = { 203,  75,  22 },
180 	[VTE_COLOR_LIGHT_GREEN]   = {  88, 110, 117 },
181 	[VTE_COLOR_LIGHT_YELLOW]  = { 101, 123, 131 },
182 	[VTE_COLOR_LIGHT_BLUE]    = { 131, 148, 150 },
183 	[VTE_COLOR_LIGHT_MAGENTA] = { 108, 113, 196 },
184 	[VTE_COLOR_LIGHT_CYAN]    = { 147, 161, 161 },
185 	[VTE_COLOR_WHITE]         = { 253, 246, 227 },
186 
187 	[VTE_COLOR_FOREGROUND]    = { 238, 232, 213 },
188 	[VTE_COLOR_BACKGROUND]    = {   7,  54,  66 },
189 };
190 
191 static uint8_t color_palette_solarized_black[VTE_COLOR_NUM][3] = {
192 	[VTE_COLOR_BLACK]         = {   0,   0,   0 },
193 	[VTE_COLOR_RED]           = { 220,  50,  47 },
194 	[VTE_COLOR_GREEN]         = { 133, 153,   0 },
195 	[VTE_COLOR_YELLOW]        = { 181, 137,   0 },
196 	[VTE_COLOR_BLUE]          = {  38, 139, 210 },
197 	[VTE_COLOR_MAGENTA]       = { 211,  54, 130 },
198 	[VTE_COLOR_CYAN]          = {  42, 161, 152 },
199 	[VTE_COLOR_LIGHT_GREY]    = { 238, 232, 213 },
200 	[VTE_COLOR_DARK_GREY]     = {   0,  43,  54 },
201 	[VTE_COLOR_LIGHT_RED]     = { 203,  75,  22 },
202 	[VTE_COLOR_LIGHT_GREEN]   = {  88, 110, 117 },
203 	[VTE_COLOR_LIGHT_YELLOW]  = { 101, 123, 131 },
204 	[VTE_COLOR_LIGHT_BLUE]    = { 131, 148, 150 },
205 	[VTE_COLOR_LIGHT_MAGENTA] = { 108, 113, 196 },
206 	[VTE_COLOR_LIGHT_CYAN]    = { 147, 161, 161 },
207 	[VTE_COLOR_WHITE]         = { 253, 246, 227 },
208 
209 	[VTE_COLOR_FOREGROUND]    = { 238, 232, 213 },
210 	[VTE_COLOR_BACKGROUND]    = {   0,   0,   0 },
211 };
212 
213 static uint8_t color_palette_solarized_white[VTE_COLOR_NUM][3] = {
214 	[VTE_COLOR_BLACK]         = {   7,  54,  66 },
215 	[VTE_COLOR_RED]           = { 220,  50,  47 },
216 	[VTE_COLOR_GREEN]         = { 133, 153,   0 },
217 	[VTE_COLOR_YELLOW]        = { 181, 137,   0 },
218 	[VTE_COLOR_BLUE]          = {  38, 139, 210 },
219 	[VTE_COLOR_MAGENTA]       = { 211,  54, 130 },
220 	[VTE_COLOR_CYAN]          = {  42, 161, 152 },
221 	[VTE_COLOR_LIGHT_GREY]    = { 238, 232, 213 },
222 	[VTE_COLOR_DARK_GREY]     = {   0,  43,  54 },
223 	[VTE_COLOR_LIGHT_RED]     = { 203,  75,  22 },
224 	[VTE_COLOR_LIGHT_GREEN]   = {  88, 110, 117 },
225 	[VTE_COLOR_LIGHT_YELLOW]  = { 101, 123, 131 },
226 	[VTE_COLOR_LIGHT_BLUE]    = { 131, 148, 150 },
227 	[VTE_COLOR_LIGHT_MAGENTA] = { 108, 113, 196 },
228 	[VTE_COLOR_LIGHT_CYAN]    = { 147, 161, 161 },
229 	[VTE_COLOR_WHITE]         = { 253, 246, 227 },
230 
231 	[VTE_COLOR_FOREGROUND]    = {   7,  54,  66 },
232 	[VTE_COLOR_BACKGROUND]    = { 238, 232, 213 },
233 };
234 
235 static uint8_t color_palette_srcery[VTE_COLOR_NUM][3] = {
236 	[VTE_COLOR_BLACK]         = {  28,  27,  25 },
237 	[VTE_COLOR_RED]           = { 239,  47,  39 },
238 	[VTE_COLOR_GREEN]         = {  81, 159,  80 },
239 	[VTE_COLOR_YELLOW]        = { 251, 184,  41 },
240 	[VTE_COLOR_BLUE]          = {  44, 120, 190 },
241 	[VTE_COLOR_MAGENTA]       = { 224,  44, 109 },
242 	[VTE_COLOR_CYAN]          = {  10, 174, 179 },
243 	[VTE_COLOR_LIGHT_GREY]    = { 145, 129, 117 },
244 	[VTE_COLOR_DARK_GREY]     = {  45,  44,  41 },
245 	[VTE_COLOR_LIGHT_RED]     = { 247,  83,  65 },
246 	[VTE_COLOR_LIGHT_GREEN]   = { 152, 188,  55 },
247 	[VTE_COLOR_LIGHT_YELLOW]  = { 254, 208, 110 },
248 	[VTE_COLOR_LIGHT_BLUE]    = { 104, 168, 228 },
249 	[VTE_COLOR_LIGHT_MAGENTA] = { 255,  92, 143 },
250 	[VTE_COLOR_LIGHT_CYAN]    = {  83, 253, 233 },
251 	[VTE_COLOR_WHITE]         = { 252, 232, 195 },
252 
253 	[VTE_COLOR_FOREGROUND]    = {0xfc,0xe8,0xc3 },
254 	[VTE_COLOR_BACKGROUND]    = {0x12,0x12,0x12 },
255 };
256 
get_palette(struct tsm_vte * vte)257 static uint8_t (*get_palette(struct tsm_vte *vte))[3]
258 {
259 	if (!vte->palette_name)
260 		return color_palette;
261 
262 	if (!strcmp(vte->palette_name, "solarized"))
263 		return color_palette_solarized;
264 	if (!strcmp(vte->palette_name, "solarized-black"))
265 		return color_palette_solarized_black;
266 	if (!strcmp(vte->palette_name, "solarized-white"))
267 		return color_palette_solarized_white;
268 	if (!strcmp(vte->palette_name, "srcery"))
269 		return color_palette_srcery;
270 
271 	return color_palette;
272 }
273 
debug_log(struct tsm_vte * vte,const char * msg,...)274 void debug_log(struct tsm_vte* vte, const char* msg, ...)
275 {
276 	if (!vte || !vte->debug)
277 		return;
278 
279 	vte->debug_ofs = 0;
280 
281 	char* out;
282 	ssize_t len;
283 
284 	va_list args;
285 	va_start(args, msg);
286 		if ( (len = vasprintf(&out, msg, args)) == -1)
287 			out = NULL;
288 	va_end(args);
289 
290 	if (!out)
291 		return;
292 
293 	if (vte->debug_lines[vte->debug_pos] != NULL){
294 		free(vte->debug_lines[vte->debug_pos]);
295 	}
296 
297 	vte->debug_lines[vte->debug_pos] = out;
298 	vte->debug_pos = (vte->debug_pos + 1) % DEBUG_HISTORY;
299 	tsm_vte_update_debug(vte);
300 }
301 
302 #define DEBUG_LOG(X, Y, ...) debug_log(X, "%d:" Y, (X)->log_ctr++, ##__VA_ARGS__)
303 
304 #define STEP_ROW() { \
305 	crow++; \
306 	if (crow < rows)\
307 		 arcan_tui_move_to(*(vte->debug), 0, crow);\
308 	else\
309 		goto out;\
310 	}
311 
wrap_write(struct tsm_vte * vte,size_t crow,const char * msg)312 static size_t wrap_write(struct tsm_vte* vte, size_t crow, const char* msg)
313 {
314 	if (!msg || strlen(msg) == 0)
315 		return crow;
316 
317 	size_t rows = 0, cols = 0;
318 	arcan_tui_dimensions(*(vte->debug), &rows, &cols);
319 
320 	size_t xpos = 0;
321 	const char* cur = msg;
322 	while (*cur){
323 		size_t next = 0;
324 
325 		while (cur[next] && (cur[next] != ' ' || (next == 0 || cur[next-1] == ':')))
326 			next++;
327 
328 		if (next >= cols && cols > 1){
329 			next = cols-1;
330 		}
331 
332 		if (xpos + next >= cols){
333 			xpos = 0;
334 			STEP_ROW();
335 		}
336 
337 		arcan_tui_writeu8(*(vte->debug), (uint8_t*) cur, next, NULL);
338 		xpos += next;
339 		cur += next;
340 	}
341 
342 	STEP_ROW();
343 out:
344 	return crow;
345 }
346 
tsm_vte_update_debug(struct tsm_vte * vte)347 void tsm_vte_update_debug(struct tsm_vte* vte)
348 {
349 	char* msg = NULL;
350 
351 	if (!vte || !vte->debug)
352 		return;
353 
354 	struct tui_context* debug = *(vte->debug);
355 
356 	struct tui_screen_attr tattr = {
357 		.fg = TUI_COL_TBASE + VTE_COLOR_FOREGROUND,
358 		.bg = TUI_COL_TBASE + VTE_COLOR_BACKGROUND,
359 		.aflags = TUI_ATTR_COLOR_INDEXED
360 	};
361 	arcan_tui_defattr(debug, &vte->def_attr);
362 	arcan_tui_erase_screen(debug, false);
363 	size_t rows = 0, cols = 0, crow = 0;
364 	arcan_tui_dimensions(debug, &rows, &cols);
365 	arcan_tui_move_to(debug, 0, 0);
366 
367 	char linebuf[256];
368 	unsigned fl = vte->csi_flags;
369 	snprintf(linebuf, sizeof(linebuf), "CSI: %s%s%s%s%s%s%s%s%s%s%s debug: %s",
370 		(fl & CSI_BANG) ? "!" : "",
371 		(fl & CSI_CASH) ? "$" : "",
372 		(fl & CSI_WHAT) ? "?" : "",
373 		(fl & CSI_GT) ? ">" : "",
374 		(fl & CSI_SPACE) ? "'spce'" : "",
375 		(fl & CSI_SQUOTE) ? "'" : "",
376 		(fl & CSI_DQUOTE) ? "\"" : "",
377 		(fl & CSI_MULT) ? "*" : "",
378 		(fl & CSI_PLUS) ? "+" : "",
379 		(fl & CSI_PLUS) ? "(" : "",
380 		(fl & CSI_PLUS) ? ")" : "",
381 		(vte->debug_verbose) ? "verbose" : "normal"
382 	);
383 	arcan_tui_writeu8(debug, (uint8_t*) linebuf, strlen(linebuf), NULL);
384 	STEP_ROW();
385 
386 	const char* state = "none";
387 	switch (vte->state){
388 		case STATE_NONE: state = "none"; break;
389 		case STATE_GROUND: state = "ground"; break;
390 		case STATE_ESC: state = "esc"; break;
391 		case STATE_ESC_INT: state = "int"; break;
392 		case STATE_CSI_ENTRY: state = "entry"; break;
393 		case STATE_CSI_PARAM: state = "param"; break;
394 		case STATE_CSI_INT: state = "int"; break;
395 		case STATE_CSI_IGNORE: state = "csi-ignore"; break;
396 		case STATE_DCS_ENTRY: state = "entry"; break;
397 		case STATE_DCS_PARAM: state = "param"; break;
398 		case STATE_DCS_INT: state = "int"; break;
399 		case STATE_DCS_PASS: state = "pass"; break;
400 		case STATE_DCS_IGNORE: state = "dcs-ignore"; break;
401 		case STATE_OSC_STRING: state = "string"; break;
402 		case STATE_ST_IGNORE:	state = "st-ignore"; break;
403 	}
404 	fl = vte->flags;
405 
406 	snprintf(linebuf, sizeof(linebuf), "State: %s Flags:"
407 		" %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", state,
408 		(fl & FLAG_CURSOR_KEY_MODE) ? "ckey " : "",
409 		(fl & FLAG_KEYPAD_APPLICATION_MODE) ? "kp_app " : "",
410 		(fl & FLAG_LINE_FEED_NEW_LINE_MODE) ? "lf_nl " : "",
411 		(fl & FLAG_8BIT_MODE) ? "8b " : "",
412 		(fl & FLAG_7BIT_MODE) ? "7b " : "",
413 		(fl & FLAG_USE_C1) ? "c1 " : "",
414 		(fl & FLAG_KEYBOARD_ACTION_MODE) ? "kbd_am " : "",
415 		(fl & FLAG_INSERT_REPLACE_MODE) ? "irep " : "",
416 		(fl & FLAG_SEND_RECEIVE_MODE) ? "snd_rcv " : "",
417 		(fl & FLAG_TEXT_CURSOR_MODE) ? "txt_cursor " : "",
418 		(fl & FLAG_INVERSE_SCREEN_MODE) ? "inv_scr " : "",
419 		(fl & FLAG_ORIGIN_MODE) ? "origin " : "",
420 		(fl & FLAG_AUTO_WRAP_MODE) ? "awrap " : "",
421 		(fl & FLAG_AUTO_REPEAT_MODE) ? "arep " : "",
422 		(fl & FLAG_NATIONAL_CHARSET_MODE) ? "nch " : "",
423 		(fl & FLAG_BACKGROUND_COLOR_ERASE_MODE) ? "bgcl_er " : "",
424 		(fl & FLAG_PREPEND_ESCAPE) ? "esc_prep " : "",
425 		(fl & FLAG_TITE_INHIBIT_MODE) ? "alt_inhibit " : "",
426 		(fl & FLAG_PASTE_BRACKET) ? "bpaste " : ""
427 	);
428 	crow = wrap_write(vte, crow, linebuf);
429 
430 	fl = vte->mstate;
431 	snprintf(linebuf, sizeof(linebuf), "Mouse @(x,y): %zu, %zu Btn: %d State: "
432 		"%s%s%s%s%s%s",
433 		vte->saved_state.mouse_x, vte->saved_state.mouse_y, vte->mbutton,
434 		(fl & MOUSE_BUTTON) ? "button " : "",
435 		(fl & MOUSE_DRAG) ? "drag " : "",
436 		(fl & MOUSE_MOTION) ? "motion " : "",
437 		(fl & MOUSE_SGR) ? "sgr " : "",
438 		(fl & MOUSE_X10) ? "x10 " : "",
439 		(fl & MOUSE_RXVT) ? "rxvt " : ""
440 	);
441 	crow = wrap_write(vte, crow, linebuf);
442 
443 /* since this can be arbitrarily long, split on space unless preceeded by a
444  * colon, unless the window is so small that the word doesn't fit, since it's
445  * debugging data, just ignore utf8 - normal TUI applications would use either
446  * autowrap or apply their own wrapping rules */
447 	msg = arcan_tui_statedescr(vte->con);
448 	crow = wrap_write(vte, crow, msg);
449 
450 /* draw the current colorscheme */
451 	arcan_tui_move_to(debug, 0, crow);
452 	for (size_t i = 0; i < 16; i++){
453 		struct tui_screen_attr tattr = {
454 			.br = TUI_COL_TBASE + i,
455 			.fr = TUI_COL_TBASE + i,
456 			.aflags = TUI_ATTR_COLOR_INDEXED
457 		};
458 		arcan_tui_write(debug, (uint32_t)' ', &tattr);
459 	}
460 
461 	crow++;
462 
463 /* fill out with history logent */
464 	size_t pos = vte->debug_pos > 0 ? vte->debug_pos - 1 : DEBUG_HISTORY - 1;
465 	char* ent;
466 
467 	size_t row_lim = rows - crow;
468 	crow = rows - 1;
469 
470 	for (size_t i = 0; i < vte->debug_ofs; i++)
471 		pos = pos > 0 ? pos - 1 : DEBUG_HISTORY - 1;
472 
473 /* should reverse this direction */
474 	while ( row_lim-- && (ent = vte->debug_lines[pos]) && pos != vte->debug_pos){
475 		arcan_tui_move_to(debug, 0, crow);
476 		arcan_tui_writeu8(debug, (uint8_t*)ent, strlen(ent), NULL);
477 		crow--;
478 		pos = pos > 0 ? pos - 1 : DEBUG_HISTORY - 1;
479 	}
480 
481 #undef STEP_ROW
482 out:
483 	if (msg)
484 		free(msg);
485 
486 /* last n warnings depending on how many rows we have
487  * inputs before last synch
488  * outputs before last synch
489  * main tui settings (w, h, mode)
490  * current foreground
491  * current background
492  * mouse state
493  * wrap mode
494  * origin mode
495  * decode flags
496  */
497 }
498 
499 /* Several effects may occur when non-RGB colors are used. For instance, if bold
500  * is enabled, then a dark color code is always converted to a light color to
501  * simulate bold (even though bold may actually be supported!). To support this,
502  * we need to differentiate between a set color-code and a set rgb-color.
503  * This function actually converts a set color-code into an RGB color. This must
504  * be called before passing the attribute to the console layer so the console
505  * layer can always work with RGB values and does not have to care for color
506  * codes. */
to_rgb(struct tsm_vte * vte,bool defattr)507 static void to_rgb(struct tsm_vte *vte, bool defattr)
508 {
509 	struct tui_screen_attr* attr = defattr ? &vte->def_attr : &vte->cattr;
510 	int fgc = defattr ? vte->d_fgcode : vte->c_fgcode;
511 	int bgc = defattr ? vte->d_bgcode : vte->c_bgcode;
512 
513 	if (fgc >= 0) {
514 		/* bold causes light colors */
515 		if (TUI_HAS_ATTR((*attr), TUI_ATTR_BOLD) && fgc < 8 && !vte->faint)
516 			fgc += 8;
517 		if (fgc >= VTE_COLOR_NUM)
518 			fgc = VTE_COLOR_FOREGROUND;
519 
520 		attr->fr = TUI_COL_TBASE + fgc;
521 		attr->aflags |= TUI_ATTR_COLOR_INDEXED;
522 	}
523 
524 	if (bgc >= 0) {
525 		if (bgc >= VTE_COLOR_NUM)
526 			bgc = VTE_COLOR_BACKGROUND;
527 
528 		attr->br = TUI_COL_TBASE + bgc;
529 		attr->aflags |= TUI_ATTR_COLOR_INDEXED;
530 	}
531 }
532 
533 /*
534  * update fg or bg attribute field with the palette- lookup based on code
535  */
set_rgb(struct tsm_vte * vte,struct tui_screen_attr * attr,bool fg,int code)536 static void set_rgb(struct tsm_vte* vte,
537 	struct tui_screen_attr* attr, bool fg, int code)
538 {
539 	if (code >= VTE_COLOR_NUM)
540 		code = VTE_COLOR_FOREGROUND;
541 
542 	if (attr == &vte->def_attr){
543 		if (fg)
544 			vte->d_fgcode = code;
545 		else
546 			vte->d_bgcode = code;
547 	}
548 	else {
549 		if (fg)
550 			vte->c_fgcode = code;
551 		else
552 			vte->c_bgcode = code;
553 	}
554 
555 	if (code < 0)
556 		return;
557 
558 	if (fg){
559 		attr->fr = TUI_COL_TBASE + code;
560 		attr->aflags |= TUI_ATTR_COLOR_INDEXED;
561 	}
562 	else{
563 		attr->br = TUI_COL_TBASE + code;
564 		attr->aflags |= TUI_ATTR_COLOR_INDEXED;
565 	}
566 }
567 
568 SHL_EXPORT
tsm_vte_new(struct tsm_vte ** out,struct tui_context * con,tsm_vte_write_cb write_cb,void * data)569 int tsm_vte_new(struct tsm_vte **out, struct tui_context *con,
570 		tsm_vte_write_cb write_cb, void *data)
571 {
572 	struct tsm_vte *vte;
573 	int ret;
574 
575 	if (!out || !con || !write_cb)
576 		return -EINVAL;
577 
578 	vte = malloc(sizeof(*vte));
579 	if (!vte)
580 		return -ENOMEM;
581 
582 	memset(vte, 0, sizeof(*vte));
583 	vte->ref = 1;
584 	vte->con = con;
585 	vte->write_cb = write_cb;
586 	vte->data = data;
587 	uint8_t* palette = (uint8_t*) get_palette(vte);
588 	memcpy(vte->palette, palette, 3 * VTE_COLOR_NUM);
589 	set_rgb(vte, &vte->def_attr, true, VTE_COLOR_FOREGROUND);
590 	set_rgb(vte, &vte->def_attr, false, VTE_COLOR_BACKGROUND);
591 	memcpy(&vte->cattr, &vte->def_attr, sizeof(struct tui_screen_attr));
592 
593 	for (size_t i = 0; i < VTE_COLOR_NUM; i++)
594 		arcan_tui_set_color(vte->con, TUI_COL_TBASE+i, &palette[i * 3]);
595 
596 	ret = tsm_utf8_mach_new(&vte->mach);
597 	if (ret)
598 		goto err_free;
599 
600 	tsm_vte_reset(vte);
601 	arcan_tui_erase_screen(vte->con, false);
602 
603 	DEBUG_LOG(vte, "new vte object");
604 	arcan_tui_refinc(vte->con);
605 	*out = vte;
606 	return 0;
607 
608 err_free:
609 	free(vte);
610 	return ret;
611 }
612 
613 SHL_EXPORT
tsm_vte_ref(struct tsm_vte * vte)614 void tsm_vte_ref(struct tsm_vte *vte)
615 {
616 	if (!vte)
617 		return;
618 
619 	vte->ref++;
620 }
621 
622 SHL_EXPORT
tsm_vte_unref(struct tsm_vte * vte)623 void tsm_vte_unref(struct tsm_vte *vte)
624 {
625 	if (!vte || !vte->ref)
626 		return;
627 
628 	if (--vte->ref)
629 		return;
630 
631 	arcan_tui_refdec(vte->con);
632 	tsm_utf8_mach_free(vte->mach);
633 
634 	for (size_t i = 0; i < DEBUG_HISTORY; i++){
635 		if (vte->debug_lines[i])
636 			free(vte->debug_lines[i]);
637 	}
638 
639 	if (vte->debug){
640 		arcan_tui_destroy(*(vte->debug), NULL);
641 		*(vte->debug) = NULL;
642 		vte->debug = NULL;
643 	}
644 
645 	free(vte);
646 }
647 
648 SHL_EXPORT
tsm_vte_set_color(struct tsm_vte * vte,enum vte_color ind,const uint8_t rgb[3])649 void tsm_vte_set_color(struct tsm_vte *vte,
650 	enum vte_color ind, const uint8_t rgb[3])
651 {
652 
653 	if (ind >= VTE_COLOR_NUM || (int)ind < 0)
654 		return;
655 
656 	uint8_t rgb_rw[3];
657 	memcpy(rgb_rw, rgb, 3);
658 
659 	vte->palette[ind][0] = rgb[0];
660 	vte->palette[ind][1] = rgb[1];
661 	vte->palette[ind][2] = rgb[2];
662 	arcan_tui_set_color(vte->con, TUI_COL_TBASE + ind, rgb_rw);
663 
664 /*
665  * NOTE: this does not update the actual color on cattr/def_attr
666  */
667 }
668 
669 SHL_EXPORT
tsm_vte_get_color(struct tsm_vte * vte,enum vte_color ind,uint8_t * rgb)670 void tsm_vte_get_color(struct tsm_vte *vte,
671 	enum vte_color ind, uint8_t *rgb)
672 {
673 	if (ind >= VTE_COLOR_NUM || ind < 0)
674 		return;
675 
676 	rgb[0] = vte->palette[ind][0];
677 	rgb[1] = vte->palette[ind][1];
678 	rgb[2] = vte->palette[ind][2];
679 }
680 
681 SHL_EXPORT
tsm_vte_set_palette(struct tsm_vte * vte,const char * pstr)682 int tsm_vte_set_palette(struct tsm_vte *vte, const char *pstr)
683 {
684 	char *tmp = NULL;
685 
686 	if (!vte)
687 		return -EINVAL;
688 
689 	if (pstr) {
690 		tmp = strdup(pstr);
691 		if (!tmp)
692 			return -ENOMEM;
693 	}
694 
695 	free(vte->palette_name);
696 	vte->palette_name = tmp;
697 	uint8_t* palette = (uint8_t*) get_palette(vte);
698 	memcpy(vte->palette, palette, 3 * VTE_COLOR_NUM);
699 	set_rgb(vte, &vte->def_attr, true, VTE_COLOR_FOREGROUND);
700 	set_rgb(vte, &vte->def_attr, false, VTE_COLOR_BACKGROUND);
701 	to_rgb(vte, true);
702 	memcpy(&vte->cattr, &vte->def_attr, sizeof(vte->cattr));
703 
704 /* forward the palette into the tui context in the terminal slots */
705 	for (size_t i = 0; i < VTE_COLOR_NUM; i++)
706 		arcan_tui_set_color(vte->con, TUI_COL_TBASE+i, &palette[i * 3]);
707 
708 	arcan_tui_defattr(vte->con, &vte->def_attr);
709 	arcan_tui_erase_screen(vte->con, false);
710 
711 	return 0;
712 }
713 
714 /*
715  * Write raw byte-stream to pty.
716  * When writing data to the client we must make sure that we send the correct
717  * encoding. For backwards-compatibility reasons we should always send 7bit
718  * characters exclusively. However, when FLAG_7BIT_MODE is not set, then we can
719  * also send raw 8bit characters. For instance, in FLAG_8BIT_MODE we can use the
720  * GR characters as keyboard input and send them directly or even use the C1
721  * escape characters. In unicode mode (default) we can send multi-byte utf-8
722  * characters which are also 8bit. When sending these characters, set the \raw
723  * flag to true so this function does not perform debug checks on data we send.
724  * If debugging is disabled, these checks are also disabled and won't affect
725  * performance.
726  * For better debugging, we also use the __LINE__ and __FILE__ macros. Use the
727  * vte_write() and vte_write_raw() macros below for more convenient use.
728  *
729  * As a rule of thumb do never send 8bit characters in escape sequences and also
730  * avoid all 8bit escape codes including the C1 codes. This will guarantee that
731  * all kind of clients are always compatible to us.
732  *
733  * If SEND_RECEIVE_MODE is off (that is, local echo is on) we have to send all
734  * data directly to ourself again. However, we must avoid recursion when
735  * tsm_vte_input() itself calls vte_write*(), therefore, we increase the
736  * PARSER counter when entering tsm_vte_input() and reset it when leaving it
737  * so we never echo data that origins from tsm_vte_input().
738  * But note that SEND_RECEIVE_MODE is inherently broken for escape sequences
739  * that request answers. That is, if we send a request to the client that awaits
740  * a response and parse that request via local echo ourself, then we will also
741  * send a response to the client even though he didn't request one. This
742  * recursion fix does not avoid this but only prevents us from endless loops
743  * here. Anyway, only few applications rely on local echo so we can safely
744  * ignore this.
745  */
vte_write_debug(struct tsm_vte * vte,const char * u8,size_t len,bool raw,const char * file,int line)746 static void vte_write_debug(struct tsm_vte *vte, const char *u8, size_t len,
747 			    bool raw, const char *file, int line)
748 {
749 #ifdef BUILD_ENABLE_DEBUG
750 	/* in debug mode we check that escape sequences are always <0x7f so they
751 	 * are correctly parsed by non-unicode and non-8bit-mode clients. */
752 	size_t i;
753 
754 	if (!raw) {
755 		for (i = 0; i < len; ++i) {
756 			if (u8[i] & 0x80)
757 				DEBUG_LOG(vte,
758 					"sending 8bit character inline to client in %s:%d", file, line);
759 		}
760 	}
761 #endif
762 
763 	/* in local echo mode, directly parse the data again */
764 	if (!vte->parse_cnt && !(vte->flags & FLAG_SEND_RECEIVE_MODE)) {
765 		if (vte->flags & FLAG_PREPEND_ESCAPE)
766 			tsm_vte_input(vte, "\e", 1);
767 		tsm_vte_input(vte, u8, len);
768 	}
769 
770 	if (vte->flags & FLAG_PREPEND_ESCAPE)
771 		vte->write_cb(vte, "\e", 1, vte->data);
772 	vte->write_cb(vte, u8, len, vte->data);
773 
774 	vte->flags &= ~FLAG_PREPEND_ESCAPE;
775 }
776 
777 #define vte_write(_vte, _u8, _len) \
778 	vte_write_debug((_vte), (_u8), (_len), false, __FILE__, __LINE__)
779 #define vte_write_raw(_vte, _u8, _len) \
780 	vte_write_debug((_vte), (_u8), (_len), true, __FILE__, __LINE__)
781 
782 /* write to console */
write_console(struct tsm_vte * vte,tsm_symbol_t sym)783 static void write_console(struct tsm_vte *vte, tsm_symbol_t sym)
784 {
785 	vte->last_symbol = sym;
786 	to_rgb(vte, false);
787 	arcan_tui_write(vte->con, sym, &vte->cattr);
788 }
789 
reset_state(struct tsm_vte * vte)790 static void reset_state(struct tsm_vte *vte)
791 {
792 	vte->saved_state.cursor_x = 0;
793 	vte->saved_state.cursor_y = 0;
794 	vte->saved_state.mouse_x = 0;
795 	vte->saved_state.mouse_y = 0;
796 	vte->saved_state.mouse_state = 0;
797 	vte->mbutton = 0;
798 	vte->saved_state.origin_mode = false;
799 	vte->saved_state.wrap_mode = true;
800 	vte->saved_state.gl = &vte->g0;
801 	vte->saved_state.gr = &vte->g1;
802 
803 	vte->saved_state.c_fgcode = vte->d_fgcode;
804 	vte->saved_state.cattr.fr = vte->def_attr.fr;
805 	vte->saved_state.cattr.fg = vte->def_attr.fg;
806 	vte->saved_state.cattr.fb = vte->def_attr.fb;
807 	vte->saved_state.c_bgcode = vte->d_bgcode;
808 	vte->saved_state.cattr.br = vte->def_attr.br;
809 	vte->saved_state.cattr.bg = vte->def_attr.bg;
810 	vte->saved_state.cattr.bb = vte->def_attr.bb;
811 	vte->saved_state.cattr.aflags = 0;
812 	vte->saved_state.cattr.custom_id = 0;
813 }
814 
save_state(struct tsm_vte * vte)815 static void save_state(struct tsm_vte *vte)
816 {
817 	arcan_tui_cursorpos(vte->con,
818 		&vte->saved_state.cursor_x, &vte->saved_state.cursor_y);
819 	vte->saved_state.cattr = vte->cattr;
820 	vte->saved_state.faint = vte->faint;
821 	vte->saved_state.gl = vte->gl;
822 	vte->saved_state.gr = vte->gr;
823 	vte->saved_state.mouse_state = vte->mstate;
824 	vte->saved_state.wrap_mode = vte->flags & FLAG_AUTO_WRAP_MODE;
825 	vte->saved_state.origin_mode = vte->flags & FLAG_ORIGIN_MODE;
826 }
827 
restore_state(struct tsm_vte * vte)828 static void restore_state(struct tsm_vte *vte)
829 {
830 	arcan_tui_move_to(vte->con, vte->saved_state.cursor_x,
831 			       vte->saved_state.cursor_y);
832 	vte->cattr = vte->saved_state.cattr;
833 	to_rgb(vte, false);
834 	if (vte->flags & FLAG_BACKGROUND_COLOR_ERASE_MODE)
835 		arcan_tui_defattr(vte->con, &vte->cattr);
836 	vte->gl = vte->saved_state.gl;
837 	vte->gr = vte->saved_state.gr;
838 	vte->faint = vte->saved_state.faint;
839 	vte->mstate = vte->saved_state.mouse_state;
840 
841 	if (vte->saved_state.wrap_mode) {
842 		vte->flags |= FLAG_AUTO_WRAP_MODE;
843 		arcan_tui_set_flags(vte->con, TUI_AUTO_WRAP);
844 	} else {
845 		vte->flags &= ~FLAG_AUTO_WRAP_MODE;
846 		arcan_tui_reset_flags(vte->con, TUI_AUTO_WRAP);
847 	}
848 
849 	if (vte->saved_state.origin_mode) {
850 		vte->flags |= FLAG_ORIGIN_MODE;
851 		arcan_tui_set_flags(vte->con, TUI_REL_ORIGIN);
852 	} else {
853 		vte->flags &= ~FLAG_ORIGIN_MODE;
854 		arcan_tui_reset_flags(vte->con, TUI_REL_ORIGIN);
855 	}
856 }
857 
858 /*
859  * Reset VTE state
860  * This performs a soft reset of the VTE. That is, everything is reset to the
861  * same state as when the VTE was created. This does not affect the console,
862  * though.
863  */
864 SHL_EXPORT
tsm_vte_reset(struct tsm_vte * vte)865 void tsm_vte_reset(struct tsm_vte *vte)
866 {
867 	if (!vte)
868 		return;
869 
870 	vte->flags = 0;
871 	vte->flags |= FLAG_TEXT_CURSOR_MODE;
872 	vte->flags |= FLAG_AUTO_REPEAT_MODE;
873 	vte->flags |= FLAG_SEND_RECEIVE_MODE;
874 	vte->flags |= FLAG_AUTO_WRAP_MODE;
875 	vte->flags |= FLAG_BACKGROUND_COLOR_ERASE_MODE;
876 	vte->last_symbol = ' ';
877 	arcan_tui_reset(vte->con);
878 	arcan_tui_set_flags(vte->con, TUI_AUTO_WRAP);
879 
880 	tsm_utf8_mach_reset(vte->mach);
881 	vte->state = STATE_GROUND;
882 	vte->gl = &vte->g0;
883 	vte->gr = &vte->g1;
884 	vte->glt = NULL;
885 	vte->grt = NULL;
886 	vte->g0 = &tsm_vte_unicode_lower;
887 	vte->g1 = &tsm_vte_unicode_upper;
888 	vte->g2 = &tsm_vte_unicode_lower;
889 	vte->g3 = &tsm_vte_unicode_upper;
890 
891 	memcpy(&vte->cattr, &vte->def_attr, sizeof(vte->cattr));
892 	vte->c_fgcode = vte->d_fgcode;
893 	vte->c_bgcode = vte->d_bgcode;
894 	to_rgb(vte, false);
895 	arcan_tui_defattr(vte->con, &vte->def_attr);
896 
897 	reset_state(vte);
898 }
899 
900 SHL_EXPORT
tsm_vte_hard_reset(struct tsm_vte * vte)901 void tsm_vte_hard_reset(struct tsm_vte *vte)
902 {
903 	tsm_vte_reset(vte);
904 	arcan_tui_erase_screen(vte->con, false);
905 	arcan_tui_erase_sb(vte->con);
906 	arcan_tui_move_to(vte->con, 0, 0);
907 }
908 
mouse_wr(struct tsm_vte * vte,int btni,int press,int mods,int row,int col)909 static void mouse_wr(struct tsm_vte *vte,
910 	int btni, int press, int mods, int row, int col)
911 {
912 	size_t nw = 0;
913 	char buf[32];
914 
915 	if (vte->mstate & MOUSE_SGR){
916 		nw = snprintf(buf, 32, "\e[%d;%d;%d%c", btni | mods, col, row, press ? 'M' : 'm');
917 	}
918 	else if (vte->mstate & MOUSE_X10){
919 		if (col > 222)
920 			col -= 32;
921 		if (row > 222)
922 			row -= 32;
923 		nw = snprintf(buf, 32, "\e[<M%c%c%c", (btni | mods) + 32, col+32, row+32);
924 	}
925 	else if (vte->mstate & MOUSE_RXVT){
926 		if (!press)
927 			btni = 3;
928 
929 		nw = snprintf(buf, 32, "\e[<%d;%d;%dM", btni | mods, col, row);
930 	}
931 
932 	if (nw && nw < 32)
933 		vte_write(vte, buf, nw);
934 }
935 
936 SHL_EXPORT
tsm_vte_paste(struct tsm_vte * vte,const char * u8,size_t len)937 void tsm_vte_paste(struct tsm_vte *vte, const char *u8, size_t len)
938 {
939 	if (vte->flags & FLAG_PASTE_BRACKET){
940 		vte_write(vte, "\e[200~", 6);
941 	}
942 
943 	vte_write(vte, u8, len);
944 
945 	if (vte->flags & FLAG_PASTE_BRACKET){
946 		vte_write(vte, "\e[201~", 6);
947 	}
948 }
949 
950 SHL_EXPORT
tsm_vte_mouse_motion(struct tsm_vte * vte,int x,int y,int mods)951 void tsm_vte_mouse_motion(struct tsm_vte *vte, int x, int y, int mods)
952 {
953 	if (x == vte->saved_state.mouse_x &&
954 		y == vte->saved_state.mouse_y)
955 			return;
956 
957 /* convert mouse state mask to match protocol */
958 	int mc = 0;
959 	mc |= (mods & TSM_SHIFT_MASK)   ? 1 : 0;
960 	mc |= (mods & TSM_ALT_MASK)     ? 2 : 0;
961 	mc |= (mods & TSM_CONTROL_MASK) ? 4 : 0;
962 
963 	vte->saved_state.mouse_x = x;
964 	vte->saved_state.mouse_y = y;
965 
966 	if ( ((vte->mstate & MOUSE_DRAG) && vte->mbutton) ||
967 		((vte->mstate & MOUSE_MOTION)) ){
968 		int btnind =
969 			vte->mbutton & 0x01 ? 1 :
970 			vte->mbutton & 0x02 ? 2 :
971 			vte->mbutton & 0x04 ? 3 : 4;
972 		mouse_wr(vte, btnind-1+32, 1, mc, y+1, x+1);
973 	}
974 }
975 
976 SHL_EXPORT
tsm_vte_mouse_button(struct tsm_vte * vte,int index,bool press,int mods)977 void tsm_vte_mouse_button(struct tsm_vte *vte, int index, bool press, int mods)
978 {
979 	int old = vte->mbutton;
980 
981 /* out of buttons? */
982 	if (index < 0 || index > 5)
983 		return;
984 
985 /* modify held- mask */
986 	else if (index <= 3){
987 		if (press)
988 			vte->mbutton |= (1 << (index - 1));
989 		else
990 			vte->mbutton &= ~(1 << (index - 1));
991 	}
992 
993 /* only report on change (but not for wheel) */
994 	if (old == vte->mbutton && index < 4)
995 		return;
996 
997 	int mc = 0;
998 	mc |= (mods & TSM_SHIFT_MASK)   ? 1 : 0;
999 	mc |= (mods & TSM_ALT_MASK)     ? 2 : 0;
1000 	mc |= (mods & TSM_CONTROL_MASK) ? 4 : 0;
1001 
1002 	mouse_wr(vte, index < 4 ? index-1 : index-4+64, press, mods,
1003 		vte->saved_state.mouse_y+1, vte->saved_state.mouse_x+1);
1004 }
1005 
send_primary_da(struct tsm_vte * vte)1006 static void send_primary_da(struct tsm_vte *vte)
1007 {
1008 	vte_write(vte, "\e[?60;1;6;9;15c", 15);
1009 }
1010 
1011 /* execute control character (C0 or C1) */
do_execute(struct tsm_vte * vte,uint32_t ctrl)1012 static void do_execute(struct tsm_vte *vte, uint32_t ctrl)
1013 {
1014 	switch (ctrl) {
1015 	case 0x00: /* NUL */
1016 		/* Ignore on input */
1017 		break;
1018 	case 0x05: /* ENQ */
1019 		/* Transmit answerback message */
1020 		/* TODO: is there a better answer than ACK?  */
1021 		vte_write(vte, "\x06", 1);
1022 		break;
1023 	case 0x07: /* BEL */
1024 		/* Sound bell tone */
1025 		/* TODO: I always considered this annying, however, we
1026 		 * should at least provide some way to enable it if the
1027 		 * user *really* wants it.
1028 		 */
1029 		break;
1030 	case 0x08: /* BS */
1031 		/* Move cursor one position left */
1032 		arcan_tui_move_left(vte->con, 1);
1033 		break;
1034 	case 0x09: /* HT */
1035 		/* Move to next tab stop or end of line */
1036 		arcan_tui_tab_right(vte->con, 1);
1037 		break;
1038 	case 0x0a: /* LF */
1039 	case 0x0b: /* VT */
1040 	case 0x0c: /* FF */
1041 		/* Line feed or newline (CR/NL mode) */
1042 		if (vte->flags & FLAG_LINE_FEED_NEW_LINE_MODE)
1043 			arcan_tui_newline(vte->con);
1044 		else
1045 			arcan_tui_move_down(vte->con, 1, true);
1046 		break;
1047 	case 0x0d: /* CR */
1048 		/* Move cursor to left margin */
1049 		arcan_tui_move_line_home(vte->con);
1050 		break;
1051 	case 0x0e: /* SO */
1052 		/* Map G1 character set into GL */
1053 		vte->gl = &vte->g1;
1054 		break;
1055 	case 0x0f: /* SI */
1056 		/* Map G0 character set into GL */
1057 		vte->gl = &vte->g0;
1058 		break;
1059 	case 0x11: /* XON */
1060 		/* Resume transmission */
1061 		/* TODO */
1062 		break;
1063 	case 0x13: /* XOFF */
1064 		/* Stop transmission */
1065 		/* TODO */
1066 		break;
1067 	case 0x18: /* CAN */
1068 		/* Cancel escape sequence */
1069 		/* nothing to do here */
1070 		break;
1071 	case 0x1a: /* SUB */
1072 		/* Discard current escape sequence and show err-sym */
1073 		write_console(vte, 0xbf);
1074 		break;
1075 	case 0x1b: /* ESC */
1076 		/* Invokes an escape sequence */
1077 		/* nothing to do here */
1078 		break;
1079 	case 0x1f: /* DEL */
1080 		/* Ignored */
1081 		break;
1082 	case 0x84: /* IND */
1083 		/* Move down one row, perform scroll-up if needed */
1084 		arcan_tui_move_down(vte->con, 1, true);
1085 		break;
1086 	case 0x85: /* NEL */
1087 		/* CR/NL with scroll-up if needed */
1088 		arcan_tui_newline(vte->con);
1089 		break;
1090 	case 0x88: /* HTS */
1091 		/* Set tab stop at current position */
1092 		arcan_tui_set_tabstop(vte->con);
1093 		break;
1094 	case 0x8d: /* RI */
1095 		/* Move up one row, perform scroll-down if needed */
1096 		arcan_tui_move_up(vte->con, 1, true);
1097 		break;
1098 	case 0x8e: /* SS2 */
1099 		/* Temporarily map G2 into GL for next char only */
1100 		vte->glt = &vte->g2;
1101 		break;
1102 	case 0x8f: /* SS3 */
1103 		/* Temporarily map G3 into GL for next char only */
1104 		vte->glt = &vte->g3;
1105 		break;
1106 	case 0x9a: /* DECID */
1107 		/* Send device attributes response like ANSI DA */
1108 		send_primary_da(vte);
1109 		break;
1110 	case 0x9c: /* ST */
1111 		/* End control string */
1112 		/* nothing to do here */
1113 		break;
1114 	default:
1115 		DEBUG_LOG(vte, "unhandled control char %u", ctrl);
1116 	}
1117 }
1118 
do_clear(struct tsm_vte * vte)1119 static void do_clear(struct tsm_vte *vte)
1120 {
1121 	int i;
1122 
1123 	vte->csi_argc = 0;
1124 	for (i = 0; i < CSI_ARG_MAX; ++i)
1125 		vte->csi_argv[i] = -1;
1126 	vte->csi_flags = 0;
1127 }
1128 
do_collect(struct tsm_vte * vte,uint32_t data)1129 static void do_collect(struct tsm_vte *vte, uint32_t data)
1130 {
1131 	switch (data) {
1132 	case '!':
1133 		vte->csi_flags |= CSI_BANG;
1134 		break;
1135 	case '$':
1136 		vte->csi_flags |= CSI_CASH;
1137 		break;
1138 	case '?':
1139 		vte->csi_flags |= CSI_WHAT;
1140 		break;
1141 	case '>':
1142 		vte->csi_flags |= CSI_GT;
1143 		break;
1144 	case ' ':
1145 		vte->csi_flags |= CSI_SPACE;
1146 		break;
1147 	case '\'':
1148 		vte->csi_flags |= CSI_SQUOTE;
1149 		break;
1150 	case '"':
1151 		vte->csi_flags |= CSI_DQUOTE;
1152 		break;
1153 	case '*':
1154 		vte->csi_flags |= CSI_MULT;
1155 		break;
1156 	case '+':
1157 		vte->csi_flags |= CSI_PLUS;
1158 		break;
1159 	case '(':
1160 		vte->csi_flags |= CSI_POPEN;
1161 		break;
1162 	case ')':
1163 		vte->csi_flags |= CSI_PCLOSE;
1164 		break;
1165 	}
1166 }
1167 
do_param(struct tsm_vte * vte,uint32_t data)1168 static void do_param(struct tsm_vte *vte, uint32_t data)
1169 {
1170 	int new;
1171 
1172 	if (data == ';') {
1173 		if (vte->csi_argc < CSI_ARG_MAX)
1174 			vte->csi_argc++;
1175 		return;
1176 	}
1177 
1178 	if (vte->csi_argc >= CSI_ARG_MAX)
1179 		return;
1180 
1181 	/* avoid integer overflows; max allowed value is 16384 anyway */
1182 	if (vte->csi_argv[vte->csi_argc] > 0xffff)
1183 		return;
1184 
1185 	if (data >= '0' && data <= '9') {
1186 		new = vte->csi_argv[vte->csi_argc];
1187 		if (new <= 0)
1188 			new = data - '0';
1189 		else
1190 			new = new * 10 + data - '0';
1191 		vte->csi_argv[vte->csi_argc] = new;
1192 	}
1193 }
1194 
set_charset(struct tsm_vte * vte,tsm_vte_charset * set)1195 static bool set_charset(struct tsm_vte *vte, tsm_vte_charset *set)
1196 {
1197 	if (vte->csi_flags & CSI_POPEN)
1198 		vte->g0 = set;
1199 	else if (vte->csi_flags & CSI_PCLOSE)
1200 		vte->g1 = set;
1201 	else if (vte->csi_flags & CSI_MULT)
1202 		vte->g2 = set;
1203 	else if (vte->csi_flags & CSI_PLUS)
1204 		vte->g3 = set;
1205 	else
1206 		return false;
1207 
1208 	return true;
1209 }
1210 
do_esc(struct tsm_vte * vte,uint32_t data)1211 static void do_esc(struct tsm_vte *vte, uint32_t data)
1212 {
1213 	switch (data) {
1214 	case 'B': /* map ASCII into G0-G3 */
1215 		if (set_charset(vte, &tsm_vte_unicode_lower))
1216 			return;
1217 		break;
1218 	case '<': /* map DEC supplemental into G0-G3 */
1219 		if (set_charset(vte, &tsm_vte_dec_supplemental_graphics))
1220 			return;
1221 		break;
1222 	case '0': /* map DEC special into G0-G3 */
1223 		if (set_charset(vte, &tsm_vte_dec_special_graphics))
1224 			return;
1225 		break;
1226 	case 'A': /* map British into G0-G3 */
1227 		/* TODO: create British charset from DEC */
1228 		if (set_charset(vte, &tsm_vte_unicode_upper))
1229 			return;
1230 		break;
1231 	case '4': /* map Dutch into G0-G3 */
1232 		/* TODO: create Dutch charset from DEC */
1233 		if (set_charset(vte, &tsm_vte_unicode_upper))
1234 			return;
1235 		break;
1236 	case 'C':
1237 	case '5': /* map Finnish into G0-G3 */
1238 		/* TODO: create Finnish charset from DEC */
1239 		if (set_charset(vte, &tsm_vte_unicode_upper))
1240 			return;
1241 		break;
1242 	case 'R': /* map French into G0-G3 */
1243 		/* TODO: create French charset from DEC */
1244 		if (set_charset(vte, &tsm_vte_unicode_upper))
1245 			return;
1246 		break;
1247 	case 'Q': /* map French-Canadian into G0-G3 */
1248 		/* TODO: create French-Canadian charset from DEC */
1249 		if (set_charset(vte, &tsm_vte_unicode_upper))
1250 			return;
1251 		break;
1252 	case 'K': /* map German into G0-G3 */
1253 		/* TODO: create German charset from DEC */
1254 		if (set_charset(vte, &tsm_vte_unicode_upper))
1255 			return;
1256 		break;
1257 	case 'Y': /* map Italian into G0-G3 */
1258 		/* TODO: create Italian charset from DEC */
1259 		if (set_charset(vte, &tsm_vte_unicode_upper))
1260 			return;
1261 		break;
1262 	case 'E':
1263 	case '6': /* map Norwegian/Danish into G0-G3 */
1264 		/* TODO: create Norwegian/Danish charset from DEC */
1265 		if (set_charset(vte, &tsm_vte_unicode_upper))
1266 			return;
1267 		break;
1268 	case 'Z': /* map Spanish into G0-G3 */
1269 		/* TODO: create Spanish charset from DEC */
1270 		if (set_charset(vte, &tsm_vte_unicode_upper))
1271 			return;
1272 		break;
1273 	case 'H':
1274 	case '7': /* map Swedish into G0-G3 */
1275 		/* TODO: create Swedish charset from DEC */
1276 		if (set_charset(vte, &tsm_vte_unicode_upper))
1277 			return;
1278 		break;
1279 	case '=': /* map Swiss into G0-G3 */
1280 		/* TODO: create Swiss charset from DEC */
1281 		if (set_charset(vte, &tsm_vte_unicode_upper))
1282 			return;
1283 		break;
1284 	case 'F':
1285 		if (vte->csi_flags & CSI_SPACE) {
1286 			/* S7C1T */
1287 			/* Disable 8bit C1 mode */
1288 			vte->flags &= ~FLAG_USE_C1;
1289 			return;
1290 		}
1291 		break;
1292 	case 'G':
1293 		if (vte->csi_flags & CSI_SPACE) {
1294 			/* S8C1T */
1295 			/* Enable 8bit C1 mode */
1296 			vte->flags |= FLAG_USE_C1;
1297 			return;
1298 		}
1299 		break;
1300 	}
1301 
1302 	/* everything below is only valid without CSI flags */
1303 	if (vte->csi_flags) {
1304 		DEBUG_LOG(vte, "unhandled escape seq %u", data);
1305 		return;
1306 	}
1307 
1308 	switch (data) {
1309 	case 'D': /* IND */
1310 		/* Move down one row, perform scroll-up if needed */
1311 		arcan_tui_move_down(vte->con, 1, true);
1312 		break;
1313 	case 'E': /* NEL */
1314 		/* CR/NL with scroll-up if needed */
1315 		arcan_tui_newline(vte->con);
1316 		break;
1317 	case 'H': /* HTS */
1318 		/* Set tab stop at current position */
1319 		arcan_tui_set_tabstop(vte->con);
1320 		break;
1321 	case 'M': /* RI */
1322 		/* Move up one row, perform scroll-down if needed */
1323 		arcan_tui_move_up(vte->con, 1, true);
1324 		break;
1325 	case 'N': /* SS2 */
1326 		/* Temporarily map G2 into GL for next char only */
1327 		vte->glt = &vte->g2;
1328 		break;
1329 	case 'O': /* SS3 */
1330 		/* Temporarily map G3 into GL for next char only */
1331 		vte->glt = &vte->g3;
1332 		break;
1333 	case 'Z': /* DECID */
1334 		/* Send device attributes response like ANSI DA */
1335 		send_primary_da(vte);
1336 		break;
1337 	case '\\': /* ST */
1338 		/* End control string */
1339 		/* nothing to do here */
1340 		break;
1341 	case '~': /* LS1R */
1342 		/* Invoke G1 into GR */
1343 		vte->gr = &vte->g1;
1344 		break;
1345 	case 'n': /* LS2 */
1346 		/* Invoke G2 into GL */
1347 		vte->gl = &vte->g2;
1348 		break;
1349 	case '}': /* LS2R */
1350 		/* Invoke G2 into GR */
1351 		vte->gr = &vte->g2;
1352 		break;
1353 	case 'o': /* LS3 */
1354 		/* Invoke G3 into GL */
1355 		vte->gl = &vte->g3;
1356 		break;
1357 	case '|': /* LS3R */
1358 		/* Invoke G3 into GR */
1359 		vte->gr = &vte->g3;
1360 		break;
1361 	case '=': /* DECKPAM */
1362 		/* Set application keypad mode */
1363 		vte->flags |= FLAG_KEYPAD_APPLICATION_MODE;
1364 		break;
1365 	case '>': /* DECKPNM */
1366 		/* Set numeric keypad mode */
1367 		vte->flags &= ~FLAG_KEYPAD_APPLICATION_MODE;
1368 		break;
1369 	case 'c': /* RIS */
1370 		/* hard reset */
1371 		tsm_vte_hard_reset(vte);
1372 		break;
1373 	case '7': /* DECSC */
1374 		/* save console state */
1375 		save_state(vte);
1376 		break;
1377 	case '8': /* DECRC */
1378 		/* restore console state */
1379 		restore_state(vte);
1380 		break;
1381 	default:
1382 		DEBUG_LOG(vte, "unhandled escape seq %u", data);
1383 	}
1384 }
1385 
csi_attribute(struct tsm_vte * vte)1386 static void csi_attribute(struct tsm_vte *vte)
1387 {
1388 	static const uint8_t bval[6] = { 0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff };
1389 	unsigned int i, val;
1390 	int code;
1391 	uint8_t cr = 0, cg = 0, cb = 0;
1392 
1393 	if (vte->csi_argc <= 1 && vte->csi_argv[0] == -1) {
1394 		vte->csi_argc = 1;
1395 		vte->csi_argv[0] = 0;
1396 	}
1397 
1398 	for (i = 0; i < vte->csi_argc; ++i) {
1399 		switch (vte->csi_argv[i]) {
1400 		case -1:
1401 			break;
1402 		case 0:
1403 			vte->c_fgcode = vte->d_fgcode;
1404 			vte->cattr.fr = vte->def_attr.fr;
1405 			vte->cattr.fg = vte->def_attr.fg;
1406 			vte->cattr.fb = vte->def_attr.fb;
1407 			vte->c_bgcode = vte->d_bgcode;
1408 			vte->cattr.br = vte->def_attr.br;
1409 			vte->cattr.bg = vte->def_attr.bg;
1410 			vte->cattr.bb = vte->def_attr.bb;
1411 			vte->cattr.aflags = 0;
1412 			vte->faint = false;
1413 			break;
1414 		case 1:
1415 			vte->cattr.aflags |= TUI_ATTR_BOLD;
1416 		break;
1417 		case 2:
1418 			vte->faint = true;
1419 		break;
1420 		case 3:
1421 			vte->cattr.aflags |= TUI_ATTR_ITALIC;
1422 		break;
1423 		case 4:
1424 			vte->cattr.aflags |= TUI_ATTR_UNDERLINE;
1425 			break;
1426 		case 5:
1427 			vte->cattr.aflags |= TUI_ATTR_BLINK;
1428 			break;
1429 		case 7:
1430 			vte->cattr.aflags |= TUI_ATTR_INVERSE;
1431 			break;
1432 		case 22:
1433 			vte->cattr.aflags &= ~TUI_ATTR_BOLD;
1434 			vte->faint = false;
1435 			break;
1436 		case 23:
1437 			vte->cattr.aflags &= ~TUI_ATTR_ITALIC;
1438 			break;
1439 		case 24:
1440 			vte->cattr.aflags &= ~TUI_ATTR_UNDERLINE;
1441 			break;
1442 		case 25:
1443 			vte->cattr.aflags &= ~TUI_ATTR_BLINK;
1444 			break;
1445 		case 27:
1446 			vte->cattr.aflags &= ~TUI_ATTR_INVERSE;
1447 			break;
1448 		case 29:
1449 /* 'not crossed out' */
1450 		break;
1451 		case 30:
1452 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_BLACK);
1453 			break;
1454 		case 31:
1455 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_RED);
1456 			break;
1457 		case 32:
1458 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_GREEN);
1459 			break;
1460 		case 33:
1461 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_YELLOW);
1462 			break;
1463 		case 34:
1464 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_BLUE);
1465 			break;
1466 		case 35:
1467 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_MAGENTA);
1468 			break;
1469 		case 36:
1470 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_CYAN);
1471 			break;
1472 		case 37:
1473 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_LIGHT_GREY);
1474 			break;
1475 		case 39:
1476 			vte->c_fgcode = vte->d_fgcode;
1477 			vte->cattr.fr = vte->def_attr.fr;
1478 			vte->cattr.fg = vte->def_attr.fg;
1479 			vte->cattr.fb = vte->def_attr.fb;
1480 			break;
1481 		case 40:
1482 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_BLACK);
1483 			break;
1484 		case 41:
1485 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_RED);
1486 			break;
1487 		case 42:
1488 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_GREEN);
1489 			break;
1490 		case 43:
1491 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_YELLOW);
1492 			break;
1493 		case 44:
1494 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_BLUE);
1495 			break;
1496 		case 45:
1497 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_MAGENTA);
1498 			break;
1499 		case 46:
1500 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_CYAN);
1501 			break;
1502 		case 47:
1503 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_LIGHT_GREY);
1504 			break;
1505 		case 49:
1506 			vte->c_bgcode = vte->d_bgcode;
1507 			vte->cattr.br = vte->def_attr.br;
1508 			vte->cattr.bg = vte->def_attr.bg;
1509 			vte->cattr.bb = vte->def_attr.bb;
1510 			break;
1511 		case 90:
1512 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_DARK_GREY);
1513 			break;
1514 		case 91:
1515 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_LIGHT_RED);
1516 			break;
1517 		case 92:
1518 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_LIGHT_GREEN);
1519 			break;
1520 		case 93:
1521 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_LIGHT_YELLOW);
1522 			break;
1523 		case 94:
1524 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_LIGHT_BLUE);
1525 			break;
1526 		case 95:
1527 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_LIGHT_MAGENTA);
1528 			break;
1529 		case 96:
1530 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_LIGHT_CYAN);
1531 			break;
1532 		case 97:
1533 			set_rgb(vte, &vte->cattr, true, VTE_COLOR_WHITE);
1534 			break;
1535 		case 100:
1536 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_DARK_GREY);
1537 			break;
1538 		case 101:
1539 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_LIGHT_RED);
1540 			break;
1541 		case 102:
1542 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_LIGHT_GREEN);
1543 			break;
1544 		case 103:
1545 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_LIGHT_YELLOW);
1546 			break;
1547 		case 104:
1548 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_LIGHT_BLUE);
1549 			break;
1550 		case 105:
1551 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_LIGHT_MAGENTA);
1552 			break;
1553 		case 106:
1554 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_LIGHT_CYAN);
1555 			break;
1556 		case 107:
1557 			set_rgb(vte, &vte->cattr, false, VTE_COLOR_WHITE);
1558 			break;
1559 		case 38:
1560 			/* fallthrough */
1561 		case 48:
1562 			val = vte->csi_argv[i];
1563 			if (vte->csi_argv[i + 1] == 5) { // 256color mode
1564 				if (i + 2 >= vte->csi_argc ||
1565 					vte->csi_argv[i + 2] < 0) {
1566 					DEBUG_LOG(vte, "invalid 256color SGR");
1567 					break;
1568 				}
1569 				code = vte->csi_argv[i + 2];
1570 				if (code < 16) {
1571 					//nochange
1572 				} else if (code < 232) {
1573 					code -= 16;
1574 					cb = bval[code % 6];
1575 					code /= 6;
1576 					cg = bval[code % 6];
1577 					code /= 6;
1578 					cr = bval[code % 6];
1579 					code = -1;
1580 				} else {
1581 					code = (code - 232) * 10 + 8;
1582 					cr = code;
1583 					cg = code;
1584 					cb = code;
1585 					code = -1;
1586 				}
1587 				i += 2;
1588 			} else if (vte->csi_argv[i + 1] == 2) {  // true color mode
1589 				if (i + 4 >= vte->csi_argc ||
1590 					vte->csi_argv[i + 2] < 0 ||
1591 					vte->csi_argv[i + 3] < 0 ||
1592 					vte->csi_argv[i + 4] < 0) {
1593 						DEBUG_LOG(vte, "invalid true color SGR");
1594 						break;
1595 					}
1596 				cr = vte->csi_argv[i + 2];
1597 				cg = vte->csi_argv[i + 3];
1598 				cb = vte->csi_argv[i + 4];
1599 				code = -1;
1600 				i += 4;
1601 			} else {
1602 				DEBUG_LOG(vte, "invalid SGR");
1603 				break;
1604 			}
1605 			if (val == 38) {
1606 				vte->c_fgcode = code;
1607 				if (code >= 0){
1608 					set_rgb(vte, &vte->cattr, true, code);
1609 				}
1610 				else{
1611 					vte->cattr.aflags &= ~TUI_ATTR_COLOR_INDEXED;
1612 					vte->cattr.fr = cr;
1613 					vte->cattr.fg = cg;
1614 					vte->cattr.fb = cb;
1615 				}
1616 			} else {
1617 				vte->c_bgcode = code;
1618 				if (code >= 0){
1619 					set_rgb(vte, &vte->cattr, false, code);
1620 				}
1621 				else {
1622 					vte->cattr.aflags &= ~TUI_ATTR_COLOR_INDEXED;
1623 					vte->cattr.br = cr;
1624 					vte->cattr.bg = cg;
1625 					vte->cattr.bb = cb;
1626 				}
1627 			}
1628 			break;
1629 		default:
1630 			DEBUG_LOG(vte, "unhandled SGR attr %i",
1631 				   vte->csi_argv[i]);
1632 		}
1633 	}
1634 
1635 	to_rgb(vte, false);
1636 	if (vte->flags & FLAG_BACKGROUND_COLOR_ERASE_MODE)
1637 		arcan_tui_defattr(vte->con, &vte->cattr);
1638 }
1639 
csi_soft_reset(struct tsm_vte * vte)1640 static void csi_soft_reset(struct tsm_vte *vte)
1641 {
1642 	tsm_vte_reset(vte);
1643 }
1644 
csi_compat_mode(struct tsm_vte * vte)1645 static void csi_compat_mode(struct tsm_vte *vte)
1646 {
1647 	/* always perform soft reset */
1648 	csi_soft_reset(vte);
1649 
1650 	if (vte->csi_argv[0] == 61) {
1651 		/* Switching to VT100 compatibility mode. We do
1652 		 * not support this mode, so ignore it. In fact,
1653 		 * we are almost compatible to it, anyway, so
1654 		 * there is no need to explicitly select it.
1655 		 * However, we enable 7bit mode to avoid
1656 		 * character-table problems */
1657 		vte->flags |= FLAG_7BIT_MODE;
1658 		vte->g0 = &tsm_vte_unicode_lower;
1659 		vte->g1 = &tsm_vte_dec_supplemental_graphics;
1660 	} else if (vte->csi_argv[0] == 62 ||
1661 		   vte->csi_argv[0] == 63 ||
1662 		   vte->csi_argv[0] == 64) {
1663 		/* Switching to VT2/3/4 compatibility mode. We
1664 		 * are always compatible with this so ignore it.
1665 		 * We always send 7bit controls so we also do
1666 		 * not care for the parameter value here that
1667 		 * select the control-mode.
1668 		 * VT220 defines argument 2 as 7bit mode but
1669 		 * VT3xx up to VT5xx use it as 8bit mode. We
1670 		 * choose to conform with the latter here.
1671 		 * We also enable 8bit mode when VT220
1672 		 * compatibility is requested explicitly. */
1673 		if (vte->csi_argv[1] == 1 ||
1674 		    vte->csi_argv[1] == 2)
1675 			vte->flags |= FLAG_USE_C1;
1676 
1677 		vte->flags |= FLAG_8BIT_MODE;
1678 		vte->g0 = &tsm_vte_unicode_lower;
1679 		vte->g1 = &tsm_vte_dec_supplemental_graphics;
1680 	} else {
1681 		DEBUG_LOG(vte, "unhandled DECSCL 'p' CSI %i, switching to utf-8 mode again",
1682 			   vte->csi_argv[0]);
1683 	}
1684 }
1685 
set_reset_flag(struct tsm_vte * vte,bool set,unsigned int flag)1686 static inline void set_reset_flag(struct tsm_vte *vte, bool set,
1687 				  unsigned int flag)
1688 {
1689 	if (set)
1690 		vte->flags |= flag;
1691 	else
1692 		vte->flags &= ~flag;
1693 }
1694 
csi_mode(struct tsm_vte * vte,bool set)1695 static void csi_mode(struct tsm_vte *vte, bool set)
1696 {
1697 	unsigned int i;
1698 
1699 	for (i = 0; i < vte->csi_argc; ++i) {
1700 		if (!(vte->csi_flags & CSI_WHAT)) {
1701 			switch (vte->csi_argv[i]) {
1702 			case -1:
1703 				continue;
1704 			case 2: /* KAM */
1705 				set_reset_flag(vte, set,
1706 					       FLAG_KEYBOARD_ACTION_MODE);
1707 				continue;
1708 			case 4: /* IRM */
1709 				set_reset_flag(vte, set,
1710 					       FLAG_INSERT_REPLACE_MODE);
1711 				if (set)
1712 					arcan_tui_set_flags(vte->con,
1713 						TUI_INSERT_MODE);
1714 				else
1715 					arcan_tui_reset_flags(vte->con,
1716 						TUI_INSERT_MODE);
1717 				continue;
1718 			case 12: /* SRM */
1719 				set_reset_flag(vte, set,
1720 					       FLAG_SEND_RECEIVE_MODE);
1721 				continue;
1722 			case 20: /* LNM */
1723 				set_reset_flag(vte, set,
1724 					       FLAG_LINE_FEED_NEW_LINE_MODE);
1725 				continue;
1726 			default:
1727 				DEBUG_LOG(vte, "unknown non-DEC (Re)Set-Mode %d",
1728 					   vte->csi_argv[i]);
1729 				continue;
1730 			}
1731 		}
1732 
1733 		switch (vte->csi_argv[i]) {
1734 		case -1:
1735 			continue;
1736 		case 1: /* DECCKM */
1737 			set_reset_flag(vte, set, FLAG_CURSOR_KEY_MODE);
1738 			continue;
1739 		case 2: /* DECANM */
1740 			/* Select VT52 mode */
1741 			/* We do not support VT52 mode. Is there any reason why
1742 			 * we should support it? We ignore it here and do not
1743 			 * mark it as to-do item unless someone has strong
1744 			 * arguments to support it. */
1745 			continue;
1746 		case 3: /* DECCOLM */
1747 			/* If set, select 132 column mode, otherwise use 80
1748 			 * column mode. If neither is selected explicitly, we
1749 			 * use dynamic mode, that is, we send SIGWCH when the
1750 			 * size changes and we allow arbitrary buffer
1751 			 * dimensions. On soft-reset, we automatically fall back
1752 			 * to the default, that is, dynamic mode.
1753 			 * Dynamic-mode can be forced to a static mode in the
1754 			 * config. That is, every time dynamic-mode becomes
1755 			 * active, the terminal will be set to the dimensions
1756 			 * that were selected in the config. This allows setting
1757 			 * a fixed size for the terminal regardless of the
1758 			 * display size.
1759 			 * TODO: Implement this */
1760 			continue;
1761 		case 4: /* DECSCLM */
1762 			/* Select smooth scrolling. We do not support the
1763 			 * classic smooth scrolling because we have a scrollback
1764 			 * buffer. There is no need to implement smooth
1765 			 * scrolling so ignore this here. */
1766 			continue;
1767 		case 5: /* DECSCNM */
1768 			set_reset_flag(vte, set, FLAG_INVERSE_SCREEN_MODE);
1769 			if (set)
1770 				arcan_tui_set_flags(vte->con,
1771 						TUI_INVERSE);
1772 			else
1773 				arcan_tui_reset_flags(vte->con,
1774 						TUI_INVERSE);
1775 			continue;
1776 		case 6: /* DECOM */
1777 			set_reset_flag(vte, set, FLAG_ORIGIN_MODE);
1778 			if (set)
1779 				arcan_tui_set_flags(vte->con, TUI_REL_ORIGIN);
1780 			else
1781 				arcan_tui_reset_flags(vte->con, TUI_REL_ORIGIN);
1782 			continue;
1783 		case 7: /* DECAWM */
1784 			set_reset_flag(vte, set, FLAG_AUTO_WRAP_MODE);
1785 			if (set)
1786 				arcan_tui_set_flags(vte->con, TUI_AUTO_WRAP);
1787 			else
1788 				arcan_tui_reset_flags(vte->con, TUI_AUTO_WRAP);
1789 			continue;
1790 		case 8: /* DECARM */
1791 			set_reset_flag(vte, set, FLAG_AUTO_REPEAT_MODE);
1792 			continue;
1793 		case 9: /* X10 mouse compatibility mode */
1794 			// set_reset_flag(vte, set, FLAG_ */
1795 			continue;
1796 		case 12: /* blinking cursor */
1797 			/* TODO: implement */
1798 			continue;
1799 		case 18: /* DECPFF */
1800 			/* If set, a form feed (FF) is sent to the printer after
1801 			 * every screen that is printed. We don't have printers
1802 			 * these days directly attached to terminals so we
1803 			 * ignore this here. */
1804 			continue;
1805 		case 19: /* DECPEX */
1806 			/* If set, the full screen is printed instead of
1807 			 * scrolling region only. We have no printer so ignore
1808 			 * this mode. */
1809 			continue;
1810 
1811 /* 20: CRLF mode */
1812 
1813 		case 25: /* DECTCEM */
1814 			set_reset_flag(vte, set, FLAG_TEXT_CURSOR_MODE);
1815 			if (set)
1816 				arcan_tui_reset_flags(vte->con,
1817 						TUI_HIDE_CURSOR);
1818 			else
1819 				arcan_tui_set_flags(vte->con,
1820 						TUI_HIDE_CURSOR);
1821 			continue;
1822 
1823 /* 40: 80 -> 132 mode */
1824 
1825 		case 42: /* DECNRCM */
1826 			set_reset_flag(vte, set, FLAG_NATIONAL_CHARSET_MODE);
1827 			continue;
1828 
1829 /* 45: reverse wrap-around */
1830 
1831 		case 47: /* Alternate screen buffer */
1832 			if (vte->flags & FLAG_TITE_INHIBIT_MODE)
1833 				continue;
1834 
1835 			if (set)
1836 				arcan_tui_set_flags(vte->con, TUI_ALTERNATE);
1837 			else
1838 				arcan_tui_reset_flags(vte->con, TUI_ALTERNATE);
1839 		continue;
1840 
1841 /* 59: kanji terminal
1842  * 66: app keypad
1843  * 67: backspace as bs not del
1844  * 69: l/r margins */
1845 
1846 		case 1000:
1847 			vte->mstate = MOUSE_BUTTON;
1848 			if (0)
1849 		case 1002:
1850 			vte->mstate = MOUSE_DRAG;
1851 			if (0)
1852 		case 1003:
1853 			vte->mstate = MOUSE_MOTION;
1854 			vte->mstate |= MOUSE_X10;
1855 			if (!set)
1856 				vte->mstate = 0;
1857 			continue;
1858 		case 1006:
1859 			vte->mstate = (vte->mstate & (~MOUSE_PROTO)) |
1860 				( set ? MOUSE_SGR : MOUSE_X10);
1861 			continue;
1862 		case 1015:
1863 			vte->mstate = (vte->mstate & (~MOUSE_PROTO)) |
1864 				( set ? MOUSE_RXVT : MOUSE_X10);
1865 		break;
1866 		case 1042:
1867 			arcan_tui_message(vte->con, TUI_MESSAGE_ALERT, "");
1868 		break;
1869 
1870 /* 1001: x-mouse highlight
1871  * 1004: report focus event
1872  * 1005: UTF-8 mouse mode
1873  * 1012: set home on input
1874  * 1015: mouse-ext
1875  */
1876 		case 1047: /* Alternate screen buffer with post-erase */
1877 			if (vte->flags & FLAG_TITE_INHIBIT_MODE)
1878 				continue;
1879 
1880 			if (set) {
1881 				arcan_tui_set_flags(vte->con, TUI_ALTERNATE);
1882 			} else {
1883 				arcan_tui_erase_screen(vte->con, false);
1884 				arcan_tui_reset_flags(vte->con, TUI_ALTERNATE);
1885 			}
1886 			continue;
1887 		case 1048: /* Set/Reset alternate-screen buffer cursor */
1888 			if (vte->flags & FLAG_TITE_INHIBIT_MODE)
1889 				continue;
1890 
1891 			if (set) {
1892 					arcan_tui_cursorpos(vte->con, &vte->alt_cursor_x, &vte->alt_cursor_y);
1893 			} else {
1894 				arcan_tui_move_to(vte->con, vte->alt_cursor_x, vte->alt_cursor_y);
1895 			}
1896 			continue;
1897 		case 1049: /* Alternate screen buffer with pre-erase+cursor */
1898 			if (vte->flags & FLAG_TITE_INHIBIT_MODE)
1899 				continue;
1900 
1901 			if (set) {
1902 				arcan_tui_cursorpos(vte->con, &vte->alt_cursor_x, &vte->alt_cursor_y);
1903 				arcan_tui_set_flags(vte->con, TUI_ALTERNATE);
1904 				arcan_tui_erase_screen(vte->con, false);
1905 			} else {
1906 				arcan_tui_erase_screen(vte->con, false);
1907 				arcan_tui_reset_flags(vte->con, TUI_ALTERNATE);
1908 				arcan_tui_move_to(vte->con, vte->alt_cursor_x, vte->alt_cursor_y);
1909 			}
1910 			continue;
1911 		case 2004: /* Bracketed paste mode, pref.postf.paste with \e[200~ \e[201~ */
1912 			set_reset_flag(vte, set, FLAG_PASTE_BRACKET);
1913 			continue;
1914 		default:
1915 			DEBUG_LOG(vte, "unknown DEC %set-Mode %d",
1916 				   set?"S":"Res", vte->csi_argv[i]);
1917 			continue;
1918 		}
1919 	}
1920 }
1921 
csi_dev_attr(struct tsm_vte * vte)1922 static void csi_dev_attr(struct tsm_vte *vte)
1923 {
1924 	if (vte->csi_argc <= 1 && vte->csi_argv[0] <= 0) {
1925 		if (vte->csi_flags == 0) {
1926 			send_primary_da(vte);
1927 			return;
1928 		} else if (vte->csi_flags & CSI_GT) {
1929 			vte_write(vte, "\e[>1;1;0c", 9);
1930 			return;
1931 		}
1932 	}
1933 
1934 	DEBUG_LOG(vte, "unhandled DA: %x %d %d %d...", vte->csi_flags,
1935 		   vte->csi_argv[0], vte->csi_argv[1], vte->csi_argv[2]);
1936 }
1937 
csi_dsr(struct tsm_vte * vte)1938 static void csi_dsr(struct tsm_vte *vte)
1939 {
1940 	char buf[64];
1941 	size_t x, y, len;
1942 
1943 	if (vte->csi_argv[0] == 5) {
1944 		vte_write(vte, "\e[0n", 4);
1945 	} else if (vte->csi_argv[0] == 6) {
1946 		arcan_tui_cursorpos(vte->con, &x, &y);
1947 		len = snprintf(buf, sizeof(buf), "\e[%zu;%zuR", y+1, x+1);
1948 		if (len >= sizeof(buf))
1949 			vte_write(vte, "\e[0;0R", 6);
1950 		else
1951 			vte_write(vte, buf, len);
1952 	}
1953 }
1954 
do_csi(struct tsm_vte * vte,uint32_t data)1955 static void do_csi(struct tsm_vte *vte, uint32_t data)
1956 {
1957 	int num, upper, lower;
1958 	int x, y;
1959 	bool protect;
1960 
1961 	if (vte->csi_argc < CSI_ARG_MAX)
1962 		vte->csi_argc++;
1963 
1964 	switch (data) {
1965 	case 'A': /* CUU */
1966 		/* move cursor up */
1967 		num = vte->csi_argv[0];
1968 		if (num <= 0)
1969 			num = 1;
1970 		arcan_tui_move_up(vte->con, num, false);
1971 		break;
1972 	case 'B': /* CUD */
1973 		/* move cursor down */
1974 		num = vte->csi_argv[0];
1975 		if (num <= 0)
1976 			num = 1;
1977 		arcan_tui_move_down(vte->con, num, false);
1978 		break;
1979 	case 'C': /* CUF */
1980 		/* move cursor forward */
1981 		num = vte->csi_argv[0];
1982 		if (num <= 0)
1983 			num = 1;
1984 		arcan_tui_move_right(vte->con, num);
1985 		break;
1986 	case 'D': /* CUB */
1987 		/* move cursor backward */
1988 		num = vte->csi_argv[0];
1989 		if (num <= 0)
1990 			num = 1;
1991 		arcan_tui_move_left(vte->con, num);
1992 		break;
1993 	case 'b': /* REP */
1994 			num = vte->csi_argv[0];
1995 			if (num <= 0)
1996 				num = 1;
1997 			while(num--)
1998 				write_console(vte, vte->last_symbol);
1999 	break;
2000 	case 'd':{ /* VPA */
2001 		/* Vertical Line Position Absolute */
2002 		num = vte->csi_argv[0];
2003 		if (num <= 0)
2004 			num = 1;
2005 		size_t cx, cy;
2006 		arcan_tui_cursorpos(vte->con, &cx, &cy);
2007 		x = cx; y = cy;
2008 		arcan_tui_move_to(vte->con, x, num - 1);
2009 		break;
2010 	}
2011 	case 'e':{ /* VPR */
2012 		/* Vertical Line Position Relative */
2013 		num = vte->csi_argv[0];
2014 		if (num <= 0)
2015 			num = 1;
2016 		size_t cx, cy;
2017 		arcan_tui_cursorpos(vte->con, &cx, &cy);
2018 		x = cx; y = cy;
2019 		arcan_tui_move_to(vte->con, x, y + num);
2020 	break;
2021 	}
2022 	case 'H': /* CUP */
2023 	case 'f': /* HVP */
2024 		/* position cursor */
2025 		x = vte->csi_argv[0];
2026 		if (x <= 0)
2027 			x = 1;
2028 		y = vte->csi_argv[1];
2029 		if (y <= 0)
2030 			y = 1;
2031 		arcan_tui_move_to(vte->con, y - 1, x - 1);
2032 		break;
2033 	case 'G':{ /* CHA */
2034 		/* Cursor Character Absolute */
2035 		num = vte->csi_argv[0];
2036 		if (num <= 0)
2037 			num = 1;
2038 		size_t cx, cy;
2039 		arcan_tui_cursorpos(vte->con, &cx, &cy);
2040 		x = cx; y = cy;
2041 		arcan_tui_move_to(vte->con, num - 1, y);
2042 	break;
2043 	}
2044 	case 'J':
2045 		if (vte->csi_flags & CSI_WHAT)
2046 			protect = true;
2047 		else
2048 			protect = false;
2049 
2050 		if (vte->csi_argv[0] <= 0)
2051 			arcan_tui_erase_cursor_to_screen(vte->con,
2052 							      protect);
2053 		else if (vte->csi_argv[0] == 1)
2054 			arcan_tui_erase_screen_to_cursor(vte->con,
2055 							      protect);
2056 		else if (vte->csi_argv[0] == 2)
2057 			arcan_tui_erase_screen(vte->con, protect);
2058 		else
2059 			DEBUG_LOG(vte, "unknown parameter to CSI-J: %d",
2060 				   vte->csi_argv[0]);
2061 		break;
2062 	case 'K':
2063 		if (vte->csi_flags & CSI_WHAT)
2064 			protect = true;
2065 		else
2066 			protect = false;
2067 
2068 /*CTE: con, x, y, size_x - 1, cursor_y, protect) */
2069 		if (vte->csi_argv[0] <= 0)
2070 			arcan_tui_erase_cursor_to_end(vte->con, protect);
2071 		else if (vte->csi_argv[0] == 1)
2072 /* HTC: 0, cursor_y, cursor_x, cursor_y, protet) */
2073 			arcan_tui_erase_home_to_cursor(vte->con, protect);
2074 		else if (vte->csi_argv[0] == 2)
2075 /* CL: 0, y, size_x - 1, y, protect */
2076 			arcan_tui_erase_current_line(vte->con, protect);
2077 		else
2078 			DEBUG_LOG(vte, "unknown parameter to CSI-K: %d",
2079 				   vte->csi_argv[0]);
2080 		break;
2081 	case 'X': /* ECH */
2082 		/* erase characters */
2083 		num = vte->csi_argv[0];
2084 		if (num <= 0)
2085 			num = 1;
2086 		arcan_tui_erase_chars(vte->con, num);
2087 		break;
2088 	case 'm':
2089 		csi_attribute(vte);
2090 		break;
2091 	case 'p':
2092 		if (vte->csi_flags & CSI_GT) {
2093 			/* xterm: select X11 visual cursor mode */
2094 			csi_soft_reset(vte);
2095 		} else if (vte->csi_flags & CSI_BANG) {
2096 			/* DECSTR: Soft Reset */
2097 			csi_soft_reset(vte);
2098 		} else if (vte->csi_flags & CSI_CASH) {
2099 			/* DECRQM: Request DEC Private Mode */
2100 			/* If CSI_WHAT is set, then enable,
2101 			 * otherwise disable */
2102 			csi_soft_reset(vte);
2103 		} else {
2104 			/* DECSCL: Compatibility Level */
2105 			/* Sometimes CSI_DQUOTE is set here, too */
2106 			csi_compat_mode(vte);
2107 		}
2108 		break;
2109 	case 'h': /* SM: Set Mode */
2110 		csi_mode(vte, true);
2111 		break;
2112 	case 'l': /* RM: Reset Mode */
2113 		csi_mode(vte, false);
2114 		break;
2115 	case 'r': /* DECSTBM */
2116 		/* set margin size */
2117 		upper = vte->csi_argv[0];
2118 		if (upper < 0)
2119 			upper = 0;
2120 		lower = vte->csi_argv[1];
2121 		if (lower < 0)
2122 			lower = 0;
2123 		arcan_tui_set_margins(vte->con, upper, lower);
2124 		arcan_tui_move_to(vte->con, 0, 0);
2125 		break;
2126 	case 'c': /* DA */
2127 		/* device attributes */
2128 		csi_dev_attr(vte);
2129 		break;
2130 	case 'L': /* IL */
2131 		/* insert lines */
2132 		num = vte->csi_argv[0];
2133 		if (num <= 0)
2134 			num = 1;
2135 		arcan_tui_insert_lines(vte->con, num);
2136 		break;
2137 	case 'M': /* DL */
2138 		/* delete lines */
2139 		num = vte->csi_argv[0];
2140 		if (num <= 0)
2141 			num = 1;
2142 		arcan_tui_delete_lines(vte->con, num);
2143 		break;
2144 	case 'g': /* TBC */
2145 		/* tabulation clear */
2146 		num = vte->csi_argv[0];
2147 		if (num <= 0)
2148 			arcan_tui_reset_tabstop(vte->con);
2149 		else if (num == 3)
2150 			arcan_tui_reset_all_tabstops(vte->con);
2151 		else
2152 			DEBUG_LOG(vte, "invalid parameter %d to TBC CSI", num);
2153 		break;
2154 	case '@': /* ICH */
2155 		/* insert characters */
2156 		num = vte->csi_argv[0];
2157 		if (num <= 0)
2158 			num = 1;
2159 		arcan_tui_insert_chars(vte->con, num);
2160 		break;
2161 	case 'P': /* DCH */
2162 		/* delete characters */
2163 		num = vte->csi_argv[0];
2164 		if (num <= 0)
2165 			num = 1;
2166 		arcan_tui_delete_chars(vte->con, num);
2167 		break;
2168 	case 'Z': /* CBT */
2169 		/* cursor horizontal backwards tab */
2170 		num = vte->csi_argv[0];
2171 		if (num <= 0)
2172 			num = 1;
2173 		arcan_tui_tab_left(vte->con, num);
2174 		break;
2175 	case 'I': /* CHT */
2176 		/* cursor horizontal forward tab */
2177 		num = vte->csi_argv[0];
2178 		if (num <= 0)
2179 			num = 1;
2180 		arcan_tui_tab_right(vte->con, num);
2181 		break;
2182 	case 'n': /* DSR */
2183 		/* device status reports */
2184 		csi_dsr(vte);
2185 		break;
2186 	case 'S': /* SU */
2187 		/* scroll up */
2188 		num = vte->csi_argv[0];
2189 		if (num <= 0)
2190 			num = 1;
2191 		arcan_tui_scroll_up(vte->con, num);
2192 		break;
2193 	case 'T': /* SD */
2194 		/* scroll down */
2195 		num = vte->csi_argv[0];
2196 		if (num <= 0)
2197 			num = 1;
2198 		arcan_tui_scroll_down(vte->con, num);
2199 		break;
2200 	default:
2201 		DEBUG_LOG(vte, "unhandled CSI sequence %c", data);
2202 	}
2203 }
2204 
2205 /* map a character according to current GL and GR maps */
vte_map(struct tsm_vte * vte,uint32_t val)2206 static uint32_t vte_map(struct tsm_vte *vte, uint32_t val)
2207 {
2208 	/* 32, 127, 160 and 255 map to identity like all values >255 */
2209 	switch (val) {
2210 	case 33 ... 126:
2211 		if (vte->glt) {
2212 			val = (**vte->glt)[val - 32];
2213 			vte->glt = NULL;
2214 		} else {
2215 			val = (**vte->gl)[val - 32];
2216 		}
2217 		break;
2218 	case 161 ... 254:
2219 		if (vte->grt) {
2220 			val = (**vte->grt)[val - 160];
2221 			vte->grt = NULL;
2222 		} else {
2223 			val = (**vte->gr)[val - 160];
2224 		}
2225 		break;
2226 	}
2227 
2228 	return val;
2229 }
2230 
2231 /* perform parser action */
do_action(struct tsm_vte * vte,uint32_t data,int action)2232 static void do_action(struct tsm_vte *vte, uint32_t data, int action)
2233 {
2234 	tsm_symbol_t sym;
2235 	if (vte->debug && vte->debug_verbose && action != ACTION_PRINT){
2236 		DEBUG_LOG(vte, "%s(%"PRIu32")", action_lut[action], data);
2237 	}
2238 
2239 	switch (action) {
2240 		case ACTION_NONE:
2241 			/* do nothing */
2242 			return;
2243 		case ACTION_IGNORE:
2244 			/* ignore character */
2245 			break;
2246 		case ACTION_PRINT:
2247 			sym = tsm_symbol_make(vte_map(vte, data));
2248 			write_console(vte, sym);
2249 			break;
2250 		case ACTION_EXECUTE:
2251 			do_execute(vte, data);
2252 			break;
2253 		case ACTION_CLEAR:
2254 			do_clear(vte);
2255 			break;
2256 		case ACTION_COLLECT:
2257 			do_collect(vte, data);
2258 			break;
2259 		case ACTION_PARAM:
2260 			do_param(vte, data);
2261 			break;
2262 		case ACTION_ESC_DISPATCH:
2263 			do_esc(vte, data);
2264 			break;
2265 		case ACTION_CSI_DISPATCH:
2266 			do_csi(vte, data);
2267 			break;
2268 		case ACTION_DCS_START:
2269 			break;
2270 		case ACTION_DCS_COLLECT:
2271 			break;
2272 		case ACTION_DCS_END:
2273 			break;
2274 /* just dumbly buffer these and callback- forward to the frontend */
2275 		case ACTION_OSC_START:
2276 			vte->colbuf_pos = 0;
2277 			break;
2278 		case ACTION_OSC_COLLECT:
2279 			vte->colbuf[vte->colbuf_pos] = data;
2280 			if (vte->colbuf_pos < vte->colbuf_sz-1)
2281 				vte->colbuf_pos++;
2282 			break;
2283 		case ACTION_OSC_END:
2284 			if (vte->colbuf_pos && vte->strcb){
2285 				vte->colbuf[vte->colbuf_pos] = '\0';
2286 				vte->strcb(vte, TSM_GROUP_OSC, vte->colbuf, vte->colbuf_pos+1,
2287 					vte->colbuf_pos == vte->colbuf_sz, vte->strcb_data);
2288 			}
2289 			break;
2290 		default:
2291 			DEBUG_LOG(vte, "invalid action %d", action);
2292 	}
2293 }
2294 
2295 /* entry actions to be performed when entering the selected state */
2296 static const int entry_action[] = {
2297 	[STATE_CSI_ENTRY] = ACTION_CLEAR,
2298 	[STATE_DCS_ENTRY] = ACTION_CLEAR,
2299 	[STATE_DCS_PASS] = ACTION_DCS_START,
2300 	[STATE_ESC] = ACTION_CLEAR,
2301 	[STATE_OSC_STRING] = ACTION_OSC_START,
2302 	[STATE_NUM] = ACTION_NONE,
2303 };
2304 
2305 /* exit actions to be performed when leaving the selected state */
2306 static const int exit_action[] = {
2307 	[STATE_DCS_PASS] = ACTION_DCS_END,
2308 	[STATE_OSC_STRING] = ACTION_OSC_END,
2309 	[STATE_NUM] = ACTION_NONE,
2310 };
2311 
tsm_vte_inseq(struct tsm_vte * vte)2312 bool tsm_vte_inseq(struct tsm_vte *vte)
2313 {
2314 	return (vte->state != STATE_NONE && vte->state != STATE_GROUND);
2315 }
2316 
2317 /* perform state transition and dispatch related actions */
do_trans(struct tsm_vte * vte,uint32_t data,int state,int act)2318 static void do_trans(struct tsm_vte *vte, uint32_t data, int state, int act)
2319 {
2320 	if (state != STATE_NONE) {
2321 		/* A state transition occurs. Perform exit-action,
2322 		 * transition-action and entry-action. Even when performing a
2323 		 * transition to the same state as the current state we do this.
2324 		 * Use STATE_NONE if this is not the desired behavior.
2325 		 */
2326 		do_action(vte, data, exit_action[vte->state]);
2327 		do_action(vte, data, act);
2328 		do_action(vte, data, entry_action[state]);
2329 		vte->state = state;
2330 	} else {
2331 		do_action(vte, data, act);
2332 	}
2333 }
2334 
2335 /*
2336  * Escape sequence parser
2337  * This parses the new input character \data. It performs state transition and
2338  * calls the right callbacks for each action.
2339  */
parse_data(struct tsm_vte * vte,uint32_t raw)2340 static void parse_data(struct tsm_vte *vte, uint32_t raw)
2341 {
2342 	/* events that may occur in any state */
2343 	switch (raw) {
2344 		case 0x18:
2345 		case 0x1a:
2346 		case 0x80 ... 0x8f:
2347 		case 0x91 ... 0x97:
2348 		case 0x99:
2349 		case 0x9a:
2350 		case 0x9c:
2351 			do_trans(vte, raw, STATE_GROUND, ACTION_EXECUTE);
2352 			return;
2353 		case 0x1b:
2354 			do_trans(vte, raw, STATE_ESC, ACTION_NONE);
2355 			return;
2356 		case 0x98:
2357 		case 0x9e:
2358 		case 0x9f:
2359 			do_trans(vte, raw, STATE_ST_IGNORE, ACTION_NONE);
2360 			return;
2361 		case 0x90:
2362 			do_trans(vte, raw, STATE_DCS_ENTRY, ACTION_NONE);
2363 			return;
2364 		case 0x9d:
2365 			do_trans(vte, raw, STATE_OSC_STRING, ACTION_NONE);
2366 			return;
2367 		case 0x9b:
2368 			do_trans(vte, raw, STATE_CSI_ENTRY, ACTION_NONE);
2369 			return;
2370 	}
2371 
2372 	/* events that depend on the current state */
2373 	switch (vte->state) {
2374 	case STATE_GROUND:
2375 		switch (raw) {
2376 		case 0x00 ... 0x17:
2377 		case 0x19:
2378 		case 0x1c ... 0x1f:
2379 		case 0x80 ... 0x8f:
2380 		case 0x91 ... 0x9a:
2381 		case 0x9c:
2382 			do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
2383 			return;
2384 		case 0x20 ... 0x7f:
2385 			do_trans(vte, raw, STATE_NONE, ACTION_PRINT);
2386 			return;
2387 		}
2388 		do_trans(vte, raw, STATE_NONE, ACTION_PRINT);
2389 		return;
2390 	case STATE_ESC:
2391 		switch (raw) {
2392 		case 0x00 ... 0x17:
2393 		case 0x19:
2394 		case 0x1c ... 0x1f:
2395 			do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
2396 			return;
2397 		case 0x7f:
2398 			do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2399 			return;
2400 		case 0x20 ... 0x2f:
2401 			do_trans(vte, raw, STATE_ESC_INT, ACTION_COLLECT);
2402 			return;
2403 		case 0x30 ... 0x4f:
2404 		case 0x51 ... 0x57:
2405 		case 0x59:
2406 		case 0x5a:
2407 		case 0x5c:
2408 		case 0x60 ... 0x7e:
2409 			do_trans(vte, raw, STATE_GROUND, ACTION_ESC_DISPATCH);
2410 			return;
2411 		case 0x5b:
2412 			do_trans(vte, raw, STATE_CSI_ENTRY, ACTION_NONE);
2413 			return;
2414 		case 0x5d:
2415 			do_trans(vte, raw, STATE_OSC_STRING, ACTION_NONE);
2416 			return;
2417 		case 0x50:
2418 			do_trans(vte, raw, STATE_DCS_ENTRY, ACTION_NONE);
2419 			return;
2420 		case 0x58:
2421 		case 0x5e:
2422 		case 0x5f:
2423 			do_trans(vte, raw, STATE_ST_IGNORE, ACTION_NONE);
2424 			return;
2425 		}
2426 		do_trans(vte, raw, STATE_ESC_INT, ACTION_COLLECT);
2427 		return;
2428 	case STATE_ESC_INT:
2429 		switch (raw) {
2430 		case 0x00 ... 0x17:
2431 		case 0x19:
2432 		case 0x1c ... 0x1f:
2433 			do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
2434 			return;
2435 		case 0x20 ... 0x2f:
2436 			do_trans(vte, raw, STATE_NONE, ACTION_COLLECT);
2437 			return;
2438 		case 0x7f:
2439 			do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2440 			return;
2441 		case 0x30 ... 0x7e:
2442 			do_trans(vte, raw, STATE_GROUND, ACTION_ESC_DISPATCH);
2443 			return;
2444 		}
2445 		do_trans(vte, raw, STATE_NONE, ACTION_COLLECT);
2446 		return;
2447 	case STATE_CSI_ENTRY:
2448 		switch (raw) {
2449 		case 0x00 ... 0x17:
2450 		case 0x19:
2451 		case 0x1c ... 0x1f:
2452 			do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
2453 			return;
2454 		case 0x7f:
2455 			do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2456 			return;
2457 		case 0x20 ... 0x2f:
2458 			do_trans(vte, raw, STATE_CSI_INT, ACTION_COLLECT);
2459 			return;
2460 		case 0x3a:
2461 			do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
2462 			return;
2463 		case 0x30 ... 0x39:
2464 		case 0x3b:
2465 			do_trans(vte, raw, STATE_CSI_PARAM, ACTION_PARAM);
2466 			return;
2467 		case 0x3c ... 0x3f:
2468 			do_trans(vte, raw, STATE_CSI_PARAM, ACTION_COLLECT);
2469 			return;
2470 		case 0x40 ... 0x7e:
2471 			do_trans(vte, raw, STATE_GROUND, ACTION_CSI_DISPATCH);
2472 			return;
2473 		}
2474 		do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
2475 		return;
2476 	case STATE_CSI_PARAM:
2477 		switch (raw) {
2478 		case 0x00 ... 0x17:
2479 		case 0x19:
2480 		case 0x1c ... 0x1f:
2481 			do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
2482 			return;
2483 		case 0x30 ... 0x39:
2484 		case 0x3b:
2485 			do_trans(vte, raw, STATE_NONE, ACTION_PARAM);
2486 			return;
2487 		case 0x7f:
2488 			do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2489 			return;
2490 		case 0x3a:
2491 		case 0x3c ... 0x3f:
2492 			do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
2493 			return;
2494 		case 0x20 ... 0x2f:
2495 			do_trans(vte, raw, STATE_CSI_INT, ACTION_COLLECT);
2496 			return;
2497 		case 0x40 ... 0x7e:
2498 			do_trans(vte, raw, STATE_GROUND, ACTION_CSI_DISPATCH);
2499 			return;
2500 		}
2501 		do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
2502 		return;
2503 	case STATE_CSI_INT:
2504 		switch (raw) {
2505 		case 0x00 ... 0x17:
2506 		case 0x19:
2507 		case 0x1c ... 0x1f:
2508 			do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
2509 			return;
2510 		case 0x20 ... 0x2f:
2511 			do_trans(vte, raw, STATE_NONE, ACTION_COLLECT);
2512 			return;
2513 		case 0x7f:
2514 			do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2515 			return;
2516 		case 0x30 ... 0x3f:
2517 			do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
2518 			return;
2519 		case 0x40 ... 0x7e:
2520 			do_trans(vte, raw, STATE_GROUND, ACTION_CSI_DISPATCH);
2521 			return;
2522 		}
2523 		do_trans(vte, raw, STATE_CSI_IGNORE, ACTION_NONE);
2524 		return;
2525 	case STATE_CSI_IGNORE:
2526 		switch (raw) {
2527 		case 0x00 ... 0x17:
2528 		case 0x19:
2529 		case 0x1c ... 0x1f:
2530 			do_trans(vte, raw, STATE_NONE, ACTION_EXECUTE);
2531 			return;
2532 		case 0x20 ... 0x3f:
2533 		case 0x7f:
2534 			do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2535 			return;
2536 		case 0x40 ... 0x7e:
2537 			do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
2538 			return;
2539 		}
2540 		do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2541 		return;
2542 	case STATE_DCS_ENTRY:
2543 		switch (raw) {
2544 		case 0x00 ... 0x17:
2545 		case 0x19:
2546 		case 0x1c ... 0x1f:
2547 		case 0x7f:
2548 			do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2549 			return;
2550 		case 0x3a:
2551 			do_trans(vte, raw, STATE_DCS_IGNORE, ACTION_NONE);
2552 			return;
2553 		case 0x20 ... 0x2f:
2554 			do_trans(vte, raw, STATE_DCS_INT, ACTION_COLLECT);
2555 			return;
2556 		case 0x30 ... 0x39:
2557 		case 0x3b:
2558 			do_trans(vte, raw, STATE_DCS_PARAM, ACTION_PARAM);
2559 			return;
2560 		case 0x3c ... 0x3f:
2561 			do_trans(vte, raw, STATE_DCS_PARAM, ACTION_COLLECT);
2562 			return;
2563 		case 0x40 ... 0x7e:
2564 			do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2565 			return;
2566 		}
2567 		do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2568 		return;
2569 	case STATE_DCS_PARAM:
2570 		switch (raw) {
2571 		case 0x00 ... 0x17:
2572 		case 0x19:
2573 		case 0x1c ... 0x1f:
2574 		case 0x7f:
2575 			do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2576 			return;
2577 		case 0x30 ... 0x39:
2578 		case 0x3b:
2579 			do_trans(vte, raw, STATE_NONE, ACTION_PARAM);
2580 			return;
2581 		case 0x3a:
2582 		case 0x3c ... 0x3f:
2583 			do_trans(vte, raw, STATE_DCS_IGNORE, ACTION_NONE);
2584 			return;
2585 		case 0x20 ... 0x2f:
2586 			do_trans(vte, raw, STATE_DCS_INT, ACTION_COLLECT);
2587 			return;
2588 		case 0x40 ... 0x7e:
2589 			do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2590 			return;
2591 		}
2592 		do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2593 		return;
2594 	case STATE_DCS_INT:
2595 		switch (raw) {
2596 		case 0x00 ... 0x17:
2597 		case 0x19:
2598 		case 0x1c ... 0x1f:
2599 		case 0x7f:
2600 			do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2601 			return;
2602 		case 0x20 ... 0x2f:
2603 			do_trans(vte, raw, STATE_NONE, ACTION_COLLECT);
2604 			return;
2605 		case 0x30 ... 0x3f:
2606 			do_trans(vte, raw, STATE_DCS_IGNORE, ACTION_NONE);
2607 			return;
2608 		case 0x40 ... 0x7e:
2609 			do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2610 			return;
2611 		}
2612 		do_trans(vte, raw, STATE_DCS_PASS, ACTION_NONE);
2613 		return;
2614 	case STATE_DCS_PASS:
2615 		switch (raw) {
2616 		case 0x00 ... 0x17:
2617 		case 0x19:
2618 		case 0x1c ... 0x1f:
2619 		case 0x20 ... 0x7e:
2620 			do_trans(vte, raw, STATE_NONE, ACTION_DCS_COLLECT);
2621 			return;
2622 		case 0x7f:
2623 			do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2624 			return;
2625 		case 0x9c:
2626 			do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
2627 			return;
2628 		}
2629 		do_trans(vte, raw, STATE_NONE, ACTION_DCS_COLLECT);
2630 		return;
2631 	case STATE_DCS_IGNORE:
2632 		switch (raw) {
2633 		case 0x00 ... 0x17:
2634 		case 0x19:
2635 		case 0x1c ... 0x1f:
2636 		case 0x20 ... 0x7f:
2637 			do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2638 			return;
2639 		case 0x9c:
2640 			do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
2641 			return;
2642 		}
2643 		do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2644 		return;
2645 	case STATE_OSC_STRING:
2646 		switch (raw) {
2647 		case 0x00 ... 0x06:
2648 		case 0x08 ... 0x17:
2649 		case 0x19:
2650 		case 0x1c ... 0x1f:
2651 			do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2652 			return;
2653 		case 0x20 ... 0x7f:
2654 			do_trans(vte, raw, STATE_NONE, ACTION_OSC_COLLECT);
2655 			return;
2656 		case 0x07:
2657 		case 0x9c:
2658 			do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
2659 			return;
2660 		}
2661 		do_trans(vte, raw, STATE_NONE, ACTION_OSC_COLLECT);
2662 		return;
2663 	case STATE_ST_IGNORE:
2664 		switch (raw) {
2665 		case 0x00 ... 0x17:
2666 		case 0x19:
2667 		case 0x1c ... 0x1f:
2668 		case 0x20 ... 0x7f:
2669 			do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2670 			return;
2671 		case 0x9c:
2672 			do_trans(vte, raw, STATE_GROUND, ACTION_NONE);
2673 			return;
2674 		}
2675 		do_trans(vte, raw, STATE_NONE, ACTION_IGNORE);
2676 		return;
2677 	}
2678 
2679 	DEBUG_LOG(vte, "unhandled input %u in state %d", raw, vte->state);
2680 }
2681 
2682 SHL_EXPORT
tsm_vte_input(struct tsm_vte * vte,const char * u8,size_t len)2683 void tsm_vte_input(struct tsm_vte *vte, const char *u8, size_t len)
2684 {
2685 	int state;
2686 	uint32_t ucs4;
2687 	size_t i;
2688 
2689 	if (!vte || !vte->con)
2690 		return;
2691 
2692 	++vte->parse_cnt;
2693 	for (i = 0; i < len; ++i) {
2694 		if (vte->flags & FLAG_7BIT_MODE) {
2695 			if (u8[i] & 0x80)
2696 				DEBUG_LOG(vte, "receiving 8bit character U+%d from pty while in 7bit mode",
2697 					   (int)u8[i]);
2698 			parse_data(vte, u8[i] & 0x7f);
2699 		} else if (vte->flags & FLAG_8BIT_MODE) {
2700 			parse_data(vte, u8[i]);
2701 		} else {
2702 			state = tsm_utf8_mach_feed(vte->mach, u8[i]);
2703 			if (state == TSM_UTF8_ACCEPT ||
2704 			    state == TSM_UTF8_REJECT) {
2705 				ucs4 = tsm_utf8_mach_get(vte->mach);
2706 				parse_data(vte, ucs4);
2707 			}
2708 		}
2709 	}
2710 }
2711 
on_key(struct tui_context * c,uint32_t keysym,uint8_t scancode,uint8_t mods,uint16_t subid,void * t)2712 static void on_key(struct tui_context* c, uint32_t keysym,
2713 	uint8_t scancode, uint8_t mods, uint16_t subid, void* t)
2714 {
2715 	struct tsm_vte* in = t;
2716 	if (keysym == TUIK_TAB){
2717 		in->debug_verbose = !in->debug_verbose;
2718 	}
2719 	else if (keysym == TUIK_J || keysym == TUIK_DOWN){
2720 		in->debug_ofs++;
2721 	}
2722 	else if (keysym == TUIK_K || keysym == TUIK_UP){
2723 		if (in->debug_ofs > 0)
2724 			in->debug_ofs--;
2725 	}
2726 	else if (keysym == TUIK_M){
2727 	}
2728 	else if (keysym == TUIK_ESCAPE){
2729 		for (size_t i = 0; i < DEBUG_HISTORY; i++){
2730 			if (in->debug_lines[i]){
2731 				free(in->debug_lines[i]);
2732 				in->debug_lines[i] = NULL;
2733 			}
2734 		}
2735 		in->debug_ofs = 0;
2736 		in->debug_pos = 0;
2737 	}
2738 }
2739 
on_resize(struct tui_context * tui,size_t neww,size_t newh,size_t cols,size_t rows,void * tag)2740 static void on_resize(struct tui_context* tui,
2741 	size_t neww, size_t newh, size_t cols, size_t rows, void* tag)
2742 {
2743 	tsm_vte_update_debug(tag);
2744 }
2745 
on_recolor(struct tui_context * tui,void * tag)2746 static void on_recolor(struct tui_context* tui, void* tag)
2747 {
2748 	tsm_vte_update_debug(tag);
2749 }
2750 
tsm_vte_debug(struct tsm_vte * in,struct tui_context ** dst,arcan_tui_conn * conn,struct tui_context * c)2751 SHL_EXPORT bool tsm_vte_debug(struct tsm_vte* in,
2752 	struct tui_context** dst, arcan_tui_conn* conn, struct tui_context* c)
2753 {
2754 	struct tui_cbcfg cbcfg = {
2755 		.tag = in,
2756 		.input_key = on_key,
2757 		.resized = on_resize,
2758 		.recolor = on_recolor
2759 	};
2760 
2761 /* already have one, let other implementations take a stab at it */
2762 	if (in->debug){
2763 		return false;
2764 	}
2765 
2766 	*dst = arcan_tui_setup(conn, c, &cbcfg, sizeof(cbcfg));
2767 
2768 	if (!*dst)
2769 		return false;
2770 
2771 /* no cursor, no scrollback, synch resize */
2772 	in->debug = dst;
2773 	arcan_tui_set_flags(*dst, TUI_ALTERNATE | TUI_HIDE_CURSOR);
2774 
2775 	tsm_vte_update_debug(in);
2776 	return true;
2777 }
2778 
2779 SHL_EXPORT
tsm_set_strhandler(struct tsm_vte * vte,tsm_str_cb cb,size_t limit,void * data)2780 void tsm_set_strhandler(struct tsm_vte *vte, tsm_str_cb cb, size_t limit, void* data)
2781 {
2782 	if (vte->strcb)
2783 		vte->strcb(vte, TSM_GROUP_FREE, NULL, 0, false, vte->strcb_data);
2784 
2785 	free(vte->colbuf);
2786 	vte->colbuf = NULL;
2787 	if (!cb)
2788 		return;
2789 
2790 	vte->colbuf = malloc(limit);
2791 	if (!vte->colbuf){
2792 		vte->strcb(vte, TSM_GROUP_FREE, NULL, 0, false, data);
2793 		return;
2794 	}
2795 
2796 	vte->colbuf_sz = limit;
2797 	vte->colbuf_pos = 0;
2798 	vte->colbuf[0] = '\0';
2799 	vte->strcb = cb;
2800 	vte->strcb_data = data;
2801 }
2802 
2803 SHL_EXPORT
tsm_vte_handle_keyboard(struct tsm_vte * vte,uint32_t keysym,uint32_t ascii,unsigned int mods,uint32_t unicode)2804 bool tsm_vte_handle_keyboard(struct tsm_vte *vte, uint32_t keysym,
2805 			     uint32_t ascii, unsigned int mods,
2806 			     uint32_t unicode)
2807 {
2808 	char val, u8[4];
2809 	size_t len;
2810 	uint32_t sym;
2811 
2812 	/* MOD1 (mostly labeled 'Alt') prepends an escape character to every
2813 	 * input that is sent by a key.
2814 	 * TODO: Transform this huge handler into a lookup table to save a lot
2815 	 * of code and make such modifiers easier to implement.
2816 	 * Also check whether altSendsEscape should be the default (xterm
2817 	 * disables this by default, why?) and whether we should implement the
2818 	 * fallback shifting that xterm does. */
2819 	if (mods & TSM_ALT_MASK)
2820 		vte->flags |= FLAG_PREPEND_ESCAPE;
2821 
2822 	/* A user might actually use multiple layouts for keyboard input. The
2823 	 * @keysym variable contains the actual keysym that the user used. But
2824 	 * if this keysym is not in the ascii range, the input handler does
2825 	 * check all other layouts that the user specified whether one of them
2826 	 * maps the key to some ASCII keysym and provides this via @ascii.
2827 	 * We always use the real keysym except when handling CTRL+<XY>
2828 	 * shortcuts we use the ascii keysym. This is for compatibility to xterm
2829 	 * et. al. so ctrl+c always works regardless of the currently active
2830 	 * keyboard layout.
2831 	 * But if no ascii-sym is found, we still use the real keysym. */
2832 	sym = ascii;
2833 	if (!sym)
2834 		sym = keysym;
2835 
2836 	if (mods & TSM_CONTROL_MASK) {
2837 		switch (sym) {
2838 		case TUIK_2:
2839 		case TUIK_SPACE:
2840 			vte_write(vte, "\x00", 1);
2841 			return true;
2842 		case TUIK_A:
2843 			vte_write(vte, "\x01", 1);
2844 			return true;
2845 		case TUIK_B:
2846 			vte_write(vte, "\x02", 1);
2847 			return true;
2848 		case TUIK_C:
2849 			vte_write(vte, "\x03", 1);
2850 			return true;
2851 		case TUIK_D:
2852 			vte_write(vte, "\x04", 1);
2853 			return true;
2854 		case TUIK_E:
2855 			vte_write(vte, "\x05", 1);
2856 			return true;
2857 		case TUIK_F:
2858 			vte_write(vte, "\x06", 1);
2859 			return true;
2860 		case TUIK_G:
2861 			vte_write(vte, "\x07", 1);
2862 			return true;
2863 		case TUIK_H:
2864 			vte_write(vte, "\x08", 1);
2865 			return true;
2866 		case TUIK_I:
2867 			vte_write(vte, "\x09", 1);
2868 			return true;
2869 		case TUIK_J:
2870 			vte_write(vte, "\x0a", 1);
2871 			return true;
2872 		case TUIK_K:
2873 			vte_write(vte, "\x0b", 1);
2874 			return true;
2875 		case TUIK_L:
2876 			vte_write(vte, "\x0c", 1);
2877 			return true;
2878 		case TUIK_M:
2879 			vte_write(vte, "\x0d", 1);
2880 			return true;
2881 		case TUIK_N:
2882 			vte_write(vte, "\x0e", 1);
2883 			return true;
2884 		case TUIK_O:
2885 			vte_write(vte, "\x0f", 1);
2886 			return true;
2887 		case TUIK_P:
2888 			vte_write(vte, "\x10", 1);
2889 			return true;
2890 		case TUIK_Q:
2891 			vte_write(vte, "\x11", 1);
2892 			return true;
2893 		case TUIK_R:
2894 			vte_write(vte, "\x12", 1);
2895 			return true;
2896 		case TUIK_S:
2897 			vte_write(vte, "\x13", 1);
2898 			return true;
2899 		case TUIK_T:
2900 			vte_write(vte, "\x14", 1);
2901 			return true;
2902 		case TUIK_U:
2903 			vte_write(vte, "\x15", 1);
2904 			return true;
2905 		case TUIK_V:
2906 			vte_write(vte, "\x16", 1);
2907 			return true;
2908 		case TUIK_W:
2909 			vte_write(vte, "\x17", 1);
2910 			return true;
2911 		case TUIK_X:
2912 			vte_write(vte, "\x18", 1);
2913 			return true;
2914 		case TUIK_Y:
2915 			vte_write(vte, "\x19", 1);
2916 			return true;
2917 		case TUIK_Z:
2918 			vte_write(vte, "\x1a", 1);
2919 			return true;
2920 		case TUIK_3:
2921 		case TUIK_KP_LEFTBRACE:
2922 			vte_write(vte, "\x1b", 1);
2923 			return true;
2924 		case TUIK_4:
2925 		case TUIK_BACKSLASH:
2926 			vte_write(vte, "\x1c", 1);
2927 			return true;
2928 		case TUIK_5:
2929 		case TUIK_KP_RIGHTBRACE:
2930 			vte_write(vte, "\x1d", 1);
2931 			return true;
2932 		case TUIK_6:
2933 		case TUIK_GRAVE:
2934 			vte_write(vte, "\x1e", 1);
2935 			return true;
2936 		case TUIK_7:
2937 		case TUIK_SLASH:
2938 			vte_write(vte, "\x1f", 1);
2939 			return true;
2940 		case TUIK_8:
2941 		case TUIK_BACKSPACE:
2942 			vte_write(vte, "\x7f", 1);
2943 			return true;
2944 		}
2945 	}
2946 
2947 /* NOTE: arcan >typically< (this varies between platform ,but ideally) does NOT
2948  * deal with numlock as a valid state (or caps lock for that matter). Such
2949  * state is up to the running set of scripts to maintain. Therefore, the
2950  * translation here ACT as numlock and is always in its "special keys" mode and
2951  * the numbers should be provided in the UTF8 field rather than as state
2952  * dependent keysyms */
2953 	switch (keysym) {
2954 		case TUIK_BACKSPACE:
2955 			vte_write(vte, "\x08", 1);
2956 			return true;
2957 		case TUIK_TAB:
2958 			vte_write(vte, "\x09", 1);
2959 			return true;
2960 /*
2961  * Some X keysyms that we don't have access to:
2962  * LINEFEED, LeftTab
2963 		case TUIK_ISO_Left_Tab:
2964 			vte_write(vte, "\e[Z", 3);
2965 			return true;
2966 		case TUIK_RETURN:
2967 			vte_write(vte, "\x0a", 1);
2968 			return true;
2969 */
2970 		case TUIK_CLEAR:
2971 			vte_write(vte, "\x0b", 1);
2972 			return true;
2973 		/*
2974 		 TODO: What should we do with this key? Sending XOFF is awful as
2975 		       there is no simple way on modern keyboards to send XON
2976 		       again. If someone wants this, we can re-enable it and set
2977 		       some flag.
2978 		case TUIK_Pause:
2979 			vte_write(vte, "\x13", 1);
2980 			return true;
2981 		*/
2982 		/*
2983 		 TODO: What should we do on scroll-lock? Sending 0x14 is what
2984 		       the specs say but it is not used today the way most
2985 		       users would expect so we disable it. If someone wants
2986 		       this, we can re-enable it and set some flag.
2987 		case TUIK_Scroll_Lock:
2988 			vte_write(vte, "\x14", 1);
2989 			return true;
2990 		*/
2991 		case TUIK_SYSREQ:
2992 			vte_write(vte, "\x15", 1);
2993 			return true;
2994 		case TUIK_ESCAPE:
2995 			vte_write(vte, "\x1b", 1);
2996 			return true;
2997 		case TUIK_KP_ENTER:
2998 			if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE) {
2999 				vte_write(vte, "\eOM", 3);
3000 				return true;
3001 			}
3002 			/* fallthrough */
3003 		case TUIK_RETURN:
3004 			if (vte->flags & FLAG_LINE_FEED_NEW_LINE_MODE)
3005 				vte_write(vte, "\x0d\x0a", 2);
3006 			else
3007 				vte_write(vte, "\x0d", 1);
3008 			return true;
3009 		case TUIK_HOME:
3010 		case TUIK_KP_7:
3011 			if (vte->flags & FLAG_CURSOR_KEY_MODE)
3012 				vte_write(vte, "\eOH", 3);
3013 			else
3014 				vte_write(vte, "\e[H", 3);
3015 			return true;
3016 		case TUIK_INSERT:
3017 		case TUIK_KP_0:
3018 			vte_write(vte, "\e[2~", 4);
3019 			return true;
3020 		case TUIK_DELETE:
3021 		case TUIK_KP_PERIOD:
3022 			vte_write(vte, "\e[3~", 4);
3023 			return true;
3024 		case TUIK_END:
3025 		case TUIK_KP_1:
3026 			if (vte->flags & FLAG_CURSOR_KEY_MODE)
3027 				vte_write(vte, "\eOF", 3);
3028 			else
3029 				vte_write(vte, "\e[F", 3);
3030 			return true;
3031 		case TUIK_PAGEUP:
3032 		case TUIK_KP_9:
3033 			vte_write(vte, "\e[5~", 4);
3034 			return true;
3035 		case TUIK_PAGEDOWN:
3036 		case TUIK_KP_3:
3037 			vte_write(vte, "\e[6~", 4);
3038 			return true;
3039 		case TUIK_UP:
3040 		case TUIK_KP_8:
3041 			if (vte->flags & FLAG_CURSOR_KEY_MODE)
3042 				vte_write(vte, "\eOA", 3);
3043 			else
3044 				vte_write(vte, "\e[A", 3);
3045 			return true;
3046 		case TUIK_DOWN:
3047 		case TUIK_KP_2:
3048 			if (vte->flags & FLAG_CURSOR_KEY_MODE)
3049 				vte_write(vte, "\eOB", 3);
3050 			else
3051 				vte_write(vte, "\e[B", 3);
3052 			return true;
3053 		case TUIK_RIGHT:
3054 		case TUIK_KP_6:
3055 			if (vte->flags & FLAG_CURSOR_KEY_MODE)
3056 				vte_write(vte, "\eOC", 3);
3057 			else
3058 				vte_write(vte, "\e[C", 3);
3059 			return true;
3060 		case TUIK_LEFT:
3061 		case TUIK_KP_4:
3062 			if (vte->flags & FLAG_CURSOR_KEY_MODE)
3063 				vte_write(vte, "\eOD", 3);
3064 			else
3065 				vte_write(vte, "\e[D", 3);
3066 			return true;
3067 		case TUIK_KP_5:
3068 			if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
3069 				vte_write(vte, "\eOu", 3);
3070 			else
3071 				vte_write(vte, "5", 1);
3072 			return true;
3073 		case TUIK_KP_MINUS:
3074 			if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
3075 				vte_write(vte, "\eOm", 3);
3076 			else
3077 				vte_write(vte, "-", 1);
3078 			return true;
3079 		case TUIK_KP_EQUALS:
3080 		case TUIK_KP_DIVIDE:
3081 			if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
3082 				vte_write(vte, "\eOj", 3);
3083 			else
3084 				vte_write(vte, "/", 1);
3085 			return true;
3086 		case TUIK_KP_MULTIPLY:
3087 			if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
3088 				vte_write(vte, "\eOo", 3);
3089 			else
3090 				vte_write(vte, "*", 1);
3091 			return true;
3092 		case TUIK_KP_PLUS:
3093 			if (vte->flags & FLAG_KEYPAD_APPLICATION_MODE)
3094 				vte_write(vte, "\eOk", 3);
3095 			else
3096 				vte_write(vte, "+", 1);
3097 			return true;
3098 /*		case TUIK_KP_Space:
3099 			vte_write(vte, " ", 1);
3100 			return true;
3101  */
3102 	/* TODO: check what to transmit for functions keys when
3103 		 * shift/ctrl etc. are pressed. Every terminal behaves
3104 		 * differently here which is really weird.
3105 		 * We now map F4 to F14 if shift is pressed and so on for all
3106 		 * keys. However, such mappings should rather be done via
3107 		 * xkb-configurations and we should instead add a flags argument
3108 		 * to the CSIs as some of the keys here already do. */
3109 		case TUIK_F1:
3110 			if (mods & TSM_SHIFT_MASK)
3111 				vte_write(vte, "\e[23~", 5);
3112 			else
3113 				vte_write(vte, "\eOP", 3);
3114 			return true;
3115 		case TUIK_F2:
3116 			if (mods & TSM_SHIFT_MASK)
3117 				vte_write(vte, "\e[24~", 5);
3118 			else
3119 				vte_write(vte, "\eOQ", 3);
3120 			return true;
3121 		case TUIK_F3:
3122 			if (mods & TSM_SHIFT_MASK)
3123 				vte_write(vte, "\e[25~", 5);
3124 			else
3125 				vte_write(vte, "\eOR", 3);
3126 			return true;
3127 		case TUIK_F4:
3128 			if (mods & TSM_SHIFT_MASK)
3129 				//vte_write(vte, "\e[1;2S", 6);
3130 				vte_write(vte, "\e[26~", 5);
3131 			else
3132 				vte_write(vte, "\eOS", 3);
3133 			return true;
3134 		case TUIK_F5:
3135 			if (mods & TSM_SHIFT_MASK)
3136 				//vte_write(vte, "\e[15;2~", 7);
3137 				vte_write(vte, "\e[28~", 5);
3138 			else
3139 				vte_write(vte, "\e[15~", 5);
3140 			return true;
3141 		case TUIK_F6:
3142 			if (mods & TSM_SHIFT_MASK)
3143 				//vte_write(vte, "\e[17;2~", 7);
3144 				vte_write(vte, "\e[29~", 5);
3145 			else
3146 				vte_write(vte, "\e[17~", 5);
3147 			return true;
3148 		case TUIK_F7:
3149 			if (mods & TSM_SHIFT_MASK)
3150 				//vte_write(vte, "\e[18;2~", 7);
3151 				vte_write(vte, "\e[31~", 5);
3152 			else
3153 				vte_write(vte, "\e[18~", 5);
3154 			return true;
3155 		case TUIK_F8:
3156 			if (mods & TSM_SHIFT_MASK)
3157 				//vte_write(vte, "\e[19;2~", 7);
3158 				vte_write(vte, "\e[32~", 5);
3159 			else
3160 				vte_write(vte, "\e[19~", 5);
3161 			return true;
3162 		case TUIK_F9:
3163 			if (mods & TSM_SHIFT_MASK)
3164 				//vte_write(vte, "\e[20;2~", 7);
3165 				vte_write(vte, "\e[33~", 5);
3166 			else
3167 				vte_write(vte, "\e[20~", 5);
3168 			return true;
3169 		case TUIK_F10:
3170 			if (mods & TSM_SHIFT_MASK)
3171 				//vte_write(vte, "\e[21;2~", 7);
3172 				vte_write(vte, "\e[34~", 5);
3173 			else
3174 				vte_write(vte, "\e[21~", 5);
3175 			return true;
3176 		case TUIK_F11:
3177 			if (mods & TSM_SHIFT_MASK)
3178 				vte_write(vte, "\e[23;2~", 7);
3179 			else
3180 				vte_write(vte, "\e[23~", 5);
3181 			return true;
3182 		case TUIK_F12:
3183 			if (mods & TSM_SHIFT_MASK)
3184 				vte_write(vte, "\e[24;2~", 7);
3185 			else
3186 				vte_write(vte, "\e[24~", 5);
3187 			return true;
3188 	}
3189 
3190 	if (unicode != TSM_VTE_INVALID) {
3191 		if (vte->flags & FLAG_7BIT_MODE) {
3192 			val = unicode;
3193 			if (unicode & 0x80) {
3194 				DEBUG_LOG(vte, "invalid keyboard input in 7bit mode U+%x; mapping to '?'",
3195 					   unicode);
3196 				val = '?';
3197 			}
3198 			vte_write(vte, &val, 1);
3199 		} else if (vte->flags & FLAG_8BIT_MODE) {
3200 			val = unicode;
3201 			if (unicode > 0xff) {
3202 				DEBUG_LOG(vte, "invalid keyboard input in 8bit mode U+%x; mapping to '?'",
3203 					   unicode);
3204 				val = '?';
3205 			}
3206 			vte_write_raw(vte, &val, 1);
3207 		}
3208 /*
3209 		this should already be handled in arcan- vte
3210 		else {
3211 			len = tsm_ucs4_to_utf8(tsm_symbol_make(unicode), u8);
3212 			vte_write_raw(vte, u8, len);
3213 		}
3214  */
3215 		return true;
3216 	}
3217 
3218 	vte->flags &= ~FLAG_PREPEND_ESCAPE;
3219 	return false;
3220 }
3221