input.c revision 1.160
1/* $OpenBSD: input.c,v 1.160 2019/09/24 20:44:58 nicm Exp $ */
2
3/*
4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20
21#include <netinet/in.h>
22
23#include <resolv.h>
24#include <stdlib.h>
25#include <string.h>
26#include <time.h>
27
28#include "tmux.h"
29
30/*
31 * Based on the description by Paul Williams at:
32 *
33 * https://vt100.net/emu/dec_ansi_parser
34 *
35 * With the following changes:
36 *
37 * - 7-bit only.
38 *
39 * - Support for UTF-8.
40 *
41 * - OSC (but not APC) may be terminated by \007 as well as ST.
42 *
43 * - A state for APC similar to OSC. Some terminals appear to use this to set
44 *   the title.
45 *
46 * - A state for the screen \033k...\033\\ sequence to rename a window. This is
47 *   pretty stupid but not supporting it is more trouble than it is worth.
48 *
49 * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
50 *   be passed to the underlying terminals.
51 */
52
53/* Input parser cell. */
54struct input_cell {
55	struct grid_cell	cell;
56	int			set;
57	int			g0set;	/* 1 if ACS */
58	int			g1set;	/* 1 if ACS */
59};
60
61/* Input parser argument. */
62struct input_param {
63	enum {
64		INPUT_MISSING,
65		INPUT_NUMBER,
66		INPUT_STRING
67	}                       type;
68	union {
69		int		num;
70		char	       *str;
71	};
72};
73
74/* Input parser context. */
75struct input_ctx {
76	struct window_pane     *wp;
77	struct screen_write_ctx ctx;
78
79	struct input_cell	cell;
80
81	struct input_cell	old_cell;
82	u_int 			old_cx;
83	u_int			old_cy;
84	int			old_mode;
85
86	u_char			interm_buf[4];
87	size_t			interm_len;
88
89	u_char			param_buf[64];
90	size_t			param_len;
91
92#define INPUT_BUF_START 32
93#define INPUT_BUF_LIMIT 1048576
94	u_char		       *input_buf;
95	size_t			input_len;
96	size_t			input_space;
97	enum {
98		INPUT_END_ST,
99		INPUT_END_BEL
100	}			input_end;
101
102	struct input_param	param_list[24];
103	u_int			param_list_len;
104
105	struct utf8_data	utf8data;
106	int			utf8started;
107
108	int			ch;
109	int			last;
110
111	int			flags;
112#define INPUT_DISCARD 0x1
113
114	const struct input_state *state;
115
116	struct event		timer;
117
118	/*
119	 * All input received since we were last in the ground state. Sent to
120	 * control clients on connection.
121	 */
122	struct evbuffer	 	*since_ground;
123};
124
125/* Helper functions. */
126struct input_transition;
127static int	input_split(struct input_ctx *);
128static int	input_get(struct input_ctx *, u_int, int, int);
129static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...);
130static void	input_set_state(struct window_pane *,
131		    const struct input_transition *);
132static void	input_reset_cell(struct input_ctx *);
133
134static void	input_osc_4(struct input_ctx *, const char *);
135static void	input_osc_10(struct input_ctx *, const char *);
136static void	input_osc_11(struct input_ctx *, const char *);
137static void	input_osc_52(struct input_ctx *, const char *);
138static void	input_osc_104(struct input_ctx *, const char *);
139
140/* Transition entry/exit handlers. */
141static void	input_clear(struct input_ctx *);
142static void	input_ground(struct input_ctx *);
143static void	input_enter_dcs(struct input_ctx *);
144static void	input_enter_osc(struct input_ctx *);
145static void	input_exit_osc(struct input_ctx *);
146static void	input_enter_apc(struct input_ctx *);
147static void	input_exit_apc(struct input_ctx *);
148static void	input_enter_rename(struct input_ctx *);
149static void	input_exit_rename(struct input_ctx *);
150
151/* Input state handlers. */
152static int	input_print(struct input_ctx *);
153static int	input_intermediate(struct input_ctx *);
154static int	input_parameter(struct input_ctx *);
155static int	input_input(struct input_ctx *);
156static int	input_c0_dispatch(struct input_ctx *);
157static int	input_esc_dispatch(struct input_ctx *);
158static int	input_csi_dispatch(struct input_ctx *);
159static void	input_csi_dispatch_rm(struct input_ctx *);
160static void	input_csi_dispatch_rm_private(struct input_ctx *);
161static void	input_csi_dispatch_sm(struct input_ctx *);
162static void	input_csi_dispatch_sm_private(struct input_ctx *);
163static void	input_csi_dispatch_winops(struct input_ctx *);
164static void	input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *);
165static void	input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *);
166static void	input_csi_dispatch_sgr(struct input_ctx *);
167static int	input_dcs_dispatch(struct input_ctx *);
168static int	input_top_bit_set(struct input_ctx *);
169static int	input_end_bel(struct input_ctx *);
170
171/* Command table comparison function. */
172static int	input_table_compare(const void *, const void *);
173
174/* Command table entry. */
175struct input_table_entry {
176	int		ch;
177	const char     *interm;
178	int		type;
179};
180
181/* Escape commands. */
182enum input_esc_type {
183	INPUT_ESC_DECALN,
184	INPUT_ESC_DECKPAM,
185	INPUT_ESC_DECKPNM,
186	INPUT_ESC_DECRC,
187	INPUT_ESC_DECSC,
188	INPUT_ESC_HTS,
189	INPUT_ESC_IND,
190	INPUT_ESC_NEL,
191	INPUT_ESC_RI,
192	INPUT_ESC_RIS,
193	INPUT_ESC_SCSG0_OFF,
194	INPUT_ESC_SCSG0_ON,
195	INPUT_ESC_SCSG1_OFF,
196	INPUT_ESC_SCSG1_ON,
197	INPUT_ESC_ST,
198};
199
200/* Escape command table. */
201static const struct input_table_entry input_esc_table[] = {
202	{ '0', "(", INPUT_ESC_SCSG0_ON },
203	{ '0', ")", INPUT_ESC_SCSG1_ON },
204	{ '7', "",  INPUT_ESC_DECSC },
205	{ '8', "",  INPUT_ESC_DECRC },
206	{ '8', "#", INPUT_ESC_DECALN },
207	{ '=', "",  INPUT_ESC_DECKPAM },
208	{ '>', "",  INPUT_ESC_DECKPNM },
209	{ 'B', "(", INPUT_ESC_SCSG0_OFF },
210	{ 'B', ")", INPUT_ESC_SCSG1_OFF },
211	{ 'D', "",  INPUT_ESC_IND },
212	{ 'E', "",  INPUT_ESC_NEL },
213	{ 'H', "",  INPUT_ESC_HTS },
214	{ 'M', "",  INPUT_ESC_RI },
215	{ '\\', "", INPUT_ESC_ST },
216	{ 'c', "",  INPUT_ESC_RIS },
217};
218
219/* Control (CSI) commands. */
220enum input_csi_type {
221	INPUT_CSI_CBT,
222	INPUT_CSI_CNL,
223	INPUT_CSI_CPL,
224	INPUT_CSI_CUB,
225	INPUT_CSI_CUD,
226	INPUT_CSI_CUF,
227	INPUT_CSI_CUP,
228	INPUT_CSI_CUU,
229	INPUT_CSI_DA,
230	INPUT_CSI_DA_TWO,
231	INPUT_CSI_DCH,
232	INPUT_CSI_DECSCUSR,
233	INPUT_CSI_DECSTBM,
234	INPUT_CSI_DL,
235	INPUT_CSI_DSR,
236	INPUT_CSI_ECH,
237	INPUT_CSI_ED,
238	INPUT_CSI_EL,
239	INPUT_CSI_HPA,
240	INPUT_CSI_ICH,
241	INPUT_CSI_IL,
242	INPUT_CSI_RCP,
243	INPUT_CSI_REP,
244	INPUT_CSI_RM,
245	INPUT_CSI_RM_PRIVATE,
246	INPUT_CSI_SCP,
247	INPUT_CSI_SD,
248	INPUT_CSI_SGR,
249	INPUT_CSI_SM,
250	INPUT_CSI_SM_PRIVATE,
251	INPUT_CSI_SU,
252	INPUT_CSI_TBC,
253	INPUT_CSI_VPA,
254	INPUT_CSI_WINOPS,
255};
256
257/* Control (CSI) command table. */
258static const struct input_table_entry input_csi_table[] = {
259	{ '@', "",  INPUT_CSI_ICH },
260	{ 'A', "",  INPUT_CSI_CUU },
261	{ 'B', "",  INPUT_CSI_CUD },
262	{ 'C', "",  INPUT_CSI_CUF },
263	{ 'D', "",  INPUT_CSI_CUB },
264	{ 'E', "",  INPUT_CSI_CNL },
265	{ 'F', "",  INPUT_CSI_CPL },
266	{ 'G', "",  INPUT_CSI_HPA },
267	{ 'H', "",  INPUT_CSI_CUP },
268	{ 'J', "",  INPUT_CSI_ED },
269	{ 'K', "",  INPUT_CSI_EL },
270	{ 'L', "",  INPUT_CSI_IL },
271	{ 'M', "",  INPUT_CSI_DL },
272	{ 'P', "",  INPUT_CSI_DCH },
273	{ 'S', "",  INPUT_CSI_SU },
274	{ 'T', "",  INPUT_CSI_SD },
275	{ 'X', "",  INPUT_CSI_ECH },
276	{ 'Z', "",  INPUT_CSI_CBT },
277	{ '`', "",  INPUT_CSI_HPA },
278	{ 'b', "",  INPUT_CSI_REP },
279	{ 'c', "",  INPUT_CSI_DA },
280	{ 'c', ">", INPUT_CSI_DA_TWO },
281	{ 'd', "",  INPUT_CSI_VPA },
282	{ 'f', "",  INPUT_CSI_CUP },
283	{ 'g', "",  INPUT_CSI_TBC },
284	{ 'h', "",  INPUT_CSI_SM },
285	{ 'h', "?", INPUT_CSI_SM_PRIVATE },
286	{ 'l', "",  INPUT_CSI_RM },
287	{ 'l', "?", INPUT_CSI_RM_PRIVATE },
288	{ 'm', "",  INPUT_CSI_SGR },
289	{ 'n', "",  INPUT_CSI_DSR },
290	{ 'q', " ", INPUT_CSI_DECSCUSR },
291	{ 'r', "",  INPUT_CSI_DECSTBM },
292	{ 's', "",  INPUT_CSI_SCP },
293	{ 't', "",  INPUT_CSI_WINOPS },
294	{ 'u', "",  INPUT_CSI_RCP },
295};
296
297/* Input transition. */
298struct input_transition {
299	int				first;
300	int				last;
301
302	int				(*handler)(struct input_ctx *);
303	const struct input_state       *state;
304};
305
306/* Input state. */
307struct input_state {
308	const char			*name;
309	void				(*enter)(struct input_ctx *);
310	void				(*exit)(struct input_ctx *);
311	const struct input_transition	*transitions;
312};
313
314/* State transitions available from all states. */
315#define INPUT_STATE_ANYWHERE \
316	{ 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
317	{ 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
318	{ 0x1b, 0x1b, NULL,		 &input_state_esc_enter }
319
320/* Forward declarations of state tables. */
321static const struct input_transition input_state_ground_table[];
322static const struct input_transition input_state_esc_enter_table[];
323static const struct input_transition input_state_esc_intermediate_table[];
324static const struct input_transition input_state_csi_enter_table[];
325static const struct input_transition input_state_csi_parameter_table[];
326static const struct input_transition input_state_csi_intermediate_table[];
327static const struct input_transition input_state_csi_ignore_table[];
328static const struct input_transition input_state_dcs_enter_table[];
329static const struct input_transition input_state_dcs_parameter_table[];
330static const struct input_transition input_state_dcs_intermediate_table[];
331static const struct input_transition input_state_dcs_handler_table[];
332static const struct input_transition input_state_dcs_escape_table[];
333static const struct input_transition input_state_dcs_ignore_table[];
334static const struct input_transition input_state_osc_string_table[];
335static const struct input_transition input_state_apc_string_table[];
336static const struct input_transition input_state_rename_string_table[];
337static const struct input_transition input_state_consume_st_table[];
338
339/* ground state definition. */
340static const struct input_state input_state_ground = {
341	"ground",
342	input_ground, NULL,
343	input_state_ground_table
344};
345
346/* esc_enter state definition. */
347static const struct input_state input_state_esc_enter = {
348	"esc_enter",
349	input_clear, NULL,
350	input_state_esc_enter_table
351};
352
353/* esc_intermediate state definition. */
354static const struct input_state input_state_esc_intermediate = {
355	"esc_intermediate",
356	NULL, NULL,
357	input_state_esc_intermediate_table
358};
359
360/* csi_enter state definition. */
361static const struct input_state input_state_csi_enter = {
362	"csi_enter",
363	input_clear, NULL,
364	input_state_csi_enter_table
365};
366
367/* csi_parameter state definition. */
368static const struct input_state input_state_csi_parameter = {
369	"csi_parameter",
370	NULL, NULL,
371	input_state_csi_parameter_table
372};
373
374/* csi_intermediate state definition. */
375static const struct input_state input_state_csi_intermediate = {
376	"csi_intermediate",
377	NULL, NULL,
378	input_state_csi_intermediate_table
379};
380
381/* csi_ignore state definition. */
382static const struct input_state input_state_csi_ignore = {
383	"csi_ignore",
384	NULL, NULL,
385	input_state_csi_ignore_table
386};
387
388/* dcs_enter state definition. */
389static const struct input_state input_state_dcs_enter = {
390	"dcs_enter",
391	input_enter_dcs, NULL,
392	input_state_dcs_enter_table
393};
394
395/* dcs_parameter state definition. */
396static const struct input_state input_state_dcs_parameter = {
397	"dcs_parameter",
398	NULL, NULL,
399	input_state_dcs_parameter_table
400};
401
402/* dcs_intermediate state definition. */
403static const struct input_state input_state_dcs_intermediate = {
404	"dcs_intermediate",
405	NULL, NULL,
406	input_state_dcs_intermediate_table
407};
408
409/* dcs_handler state definition. */
410static const struct input_state input_state_dcs_handler = {
411	"dcs_handler",
412	NULL, NULL,
413	input_state_dcs_handler_table
414};
415
416/* dcs_escape state definition. */
417static const struct input_state input_state_dcs_escape = {
418	"dcs_escape",
419	NULL, NULL,
420	input_state_dcs_escape_table
421};
422
423/* dcs_ignore state definition. */
424static const struct input_state input_state_dcs_ignore = {
425	"dcs_ignore",
426	NULL, NULL,
427	input_state_dcs_ignore_table
428};
429
430/* osc_string state definition. */
431static const struct input_state input_state_osc_string = {
432	"osc_string",
433	input_enter_osc, input_exit_osc,
434	input_state_osc_string_table
435};
436
437/* apc_string state definition. */
438static const struct input_state input_state_apc_string = {
439	"apc_string",
440	input_enter_apc, input_exit_apc,
441	input_state_apc_string_table
442};
443
444/* rename_string state definition. */
445static const struct input_state input_state_rename_string = {
446	"rename_string",
447	input_enter_rename, input_exit_rename,
448	input_state_rename_string_table
449};
450
451/* consume_st state definition. */
452static const struct input_state input_state_consume_st = {
453	"consume_st",
454	input_enter_rename, NULL, /* rename also waits for ST */
455	input_state_consume_st_table
456};
457
458/* ground state table. */
459static const struct input_transition input_state_ground_table[] = {
460	INPUT_STATE_ANYWHERE,
461
462	{ 0x00, 0x17, input_c0_dispatch, NULL },
463	{ 0x19, 0x19, input_c0_dispatch, NULL },
464	{ 0x1c, 0x1f, input_c0_dispatch, NULL },
465	{ 0x20, 0x7e, input_print,	 NULL },
466	{ 0x7f, 0x7f, NULL,		 NULL },
467	{ 0x80, 0xff, input_top_bit_set, NULL },
468
469	{ -1, -1, NULL, NULL }
470};
471
472/* esc_enter state table. */
473static const struct input_transition input_state_esc_enter_table[] = {
474	INPUT_STATE_ANYWHERE,
475
476	{ 0x00, 0x17, input_c0_dispatch,  NULL },
477	{ 0x19, 0x19, input_c0_dispatch,  NULL },
478	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
479	{ 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
480	{ 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
481	{ 0x50, 0x50, NULL,		  &input_state_dcs_enter },
482	{ 0x51, 0x57, input_esc_dispatch, &input_state_ground },
483	{ 0x58, 0x58, NULL,		  &input_state_consume_st },
484	{ 0x59, 0x59, input_esc_dispatch, &input_state_ground },
485	{ 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
486	{ 0x5b, 0x5b, NULL,		  &input_state_csi_enter },
487	{ 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
488	{ 0x5d, 0x5d, NULL,		  &input_state_osc_string },
489	{ 0x5e, 0x5e, NULL,		  &input_state_consume_st },
490	{ 0x5f, 0x5f, NULL,		  &input_state_apc_string },
491	{ 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
492	{ 0x6b, 0x6b, NULL,		  &input_state_rename_string },
493	{ 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
494	{ 0x7f, 0xff, NULL,		  NULL },
495
496	{ -1, -1, NULL, NULL }
497};
498
499/* esc_intermediate state table. */
500static const struct input_transition input_state_esc_intermediate_table[] = {
501	INPUT_STATE_ANYWHERE,
502
503	{ 0x00, 0x17, input_c0_dispatch,  NULL },
504	{ 0x19, 0x19, input_c0_dispatch,  NULL },
505	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
506	{ 0x20, 0x2f, input_intermediate, NULL },
507	{ 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
508	{ 0x7f, 0xff, NULL,		  NULL },
509
510	{ -1, -1, NULL, NULL }
511};
512
513/* csi_enter state table. */
514static const struct input_transition input_state_csi_enter_table[] = {
515	INPUT_STATE_ANYWHERE,
516
517	{ 0x00, 0x17, input_c0_dispatch,  NULL },
518	{ 0x19, 0x19, input_c0_dispatch,  NULL },
519	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
520	{ 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
521	{ 0x30, 0x39, input_parameter,	  &input_state_csi_parameter },
522	{ 0x3a, 0x3a, input_parameter,	  &input_state_csi_parameter },
523	{ 0x3b, 0x3b, input_parameter,	  &input_state_csi_parameter },
524	{ 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
525	{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
526	{ 0x7f, 0xff, NULL,		  NULL },
527
528	{ -1, -1, NULL, NULL }
529};
530
531/* csi_parameter state table. */
532static const struct input_transition input_state_csi_parameter_table[] = {
533	INPUT_STATE_ANYWHERE,
534
535	{ 0x00, 0x17, input_c0_dispatch,  NULL },
536	{ 0x19, 0x19, input_c0_dispatch,  NULL },
537	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
538	{ 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
539	{ 0x30, 0x39, input_parameter,	  NULL },
540	{ 0x3a, 0x3a, input_parameter,	  NULL },
541	{ 0x3b, 0x3b, input_parameter,	  NULL },
542	{ 0x3c, 0x3f, NULL,		  &input_state_csi_ignore },
543	{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
544	{ 0x7f, 0xff, NULL,		  NULL },
545
546	{ -1, -1, NULL, NULL }
547};
548
549/* csi_intermediate state table. */
550static const struct input_transition input_state_csi_intermediate_table[] = {
551	INPUT_STATE_ANYWHERE,
552
553	{ 0x00, 0x17, input_c0_dispatch,  NULL },
554	{ 0x19, 0x19, input_c0_dispatch,  NULL },
555	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
556	{ 0x20, 0x2f, input_intermediate, NULL },
557	{ 0x30, 0x3f, NULL,		  &input_state_csi_ignore },
558	{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
559	{ 0x7f, 0xff, NULL,		  NULL },
560
561	{ -1, -1, NULL, NULL }
562};
563
564/* csi_ignore state table. */
565static const struct input_transition input_state_csi_ignore_table[] = {
566	INPUT_STATE_ANYWHERE,
567
568	{ 0x00, 0x17, input_c0_dispatch, NULL },
569	{ 0x19, 0x19, input_c0_dispatch, NULL },
570	{ 0x1c, 0x1f, input_c0_dispatch, NULL },
571	{ 0x20, 0x3f, NULL,		 NULL },
572	{ 0x40, 0x7e, NULL,		 &input_state_ground },
573	{ 0x7f, 0xff, NULL,		 NULL },
574
575	{ -1, -1, NULL, NULL }
576};
577
578/* dcs_enter state table. */
579static const struct input_transition input_state_dcs_enter_table[] = {
580	INPUT_STATE_ANYWHERE,
581
582	{ 0x00, 0x17, NULL,		  NULL },
583	{ 0x19, 0x19, NULL,		  NULL },
584	{ 0x1c, 0x1f, NULL,		  NULL },
585	{ 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
586	{ 0x30, 0x39, input_parameter,	  &input_state_dcs_parameter },
587	{ 0x3a, 0x3a, NULL,		  &input_state_dcs_ignore },
588	{ 0x3b, 0x3b, input_parameter,	  &input_state_dcs_parameter },
589	{ 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
590	{ 0x40, 0x7e, input_input,	  &input_state_dcs_handler },
591	{ 0x7f, 0xff, NULL,		  NULL },
592
593	{ -1, -1, NULL, NULL }
594};
595
596/* dcs_parameter state table. */
597static const struct input_transition input_state_dcs_parameter_table[] = {
598	INPUT_STATE_ANYWHERE,
599
600	{ 0x00, 0x17, NULL,		  NULL },
601	{ 0x19, 0x19, NULL,		  NULL },
602	{ 0x1c, 0x1f, NULL,		  NULL },
603	{ 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
604	{ 0x30, 0x39, input_parameter,	  NULL },
605	{ 0x3a, 0x3a, NULL,		  &input_state_dcs_ignore },
606	{ 0x3b, 0x3b, input_parameter,	  NULL },
607	{ 0x3c, 0x3f, NULL,		  &input_state_dcs_ignore },
608	{ 0x40, 0x7e, input_input,	  &input_state_dcs_handler },
609	{ 0x7f, 0xff, NULL,		  NULL },
610
611	{ -1, -1, NULL, NULL }
612};
613
614/* dcs_intermediate state table. */
615static const struct input_transition input_state_dcs_intermediate_table[] = {
616	INPUT_STATE_ANYWHERE,
617
618	{ 0x00, 0x17, NULL,		  NULL },
619	{ 0x19, 0x19, NULL,		  NULL },
620	{ 0x1c, 0x1f, NULL,		  NULL },
621	{ 0x20, 0x2f, input_intermediate, NULL },
622	{ 0x30, 0x3f, NULL,		  &input_state_dcs_ignore },
623	{ 0x40, 0x7e, input_input,	  &input_state_dcs_handler },
624	{ 0x7f, 0xff, NULL,		  NULL },
625
626	{ -1, -1, NULL, NULL }
627};
628
629/* dcs_handler state table. */
630static const struct input_transition input_state_dcs_handler_table[] = {
631	/* No INPUT_STATE_ANYWHERE */
632
633	{ 0x00, 0x1a, input_input,  NULL },
634	{ 0x1b, 0x1b, NULL,	    &input_state_dcs_escape },
635	{ 0x1c, 0xff, input_input,  NULL },
636
637	{ -1, -1, NULL, NULL }
638};
639
640/* dcs_escape state table. */
641static const struct input_transition input_state_dcs_escape_table[] = {
642	/* No INPUT_STATE_ANYWHERE */
643
644	{ 0x00, 0x5b, input_input,	  &input_state_dcs_handler },
645	{ 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
646	{ 0x5d, 0xff, input_input,	  &input_state_dcs_handler },
647
648	{ -1, -1, NULL, NULL }
649};
650
651/* dcs_ignore state table. */
652static const struct input_transition input_state_dcs_ignore_table[] = {
653	INPUT_STATE_ANYWHERE,
654
655	{ 0x00, 0x17, NULL,	    NULL },
656	{ 0x19, 0x19, NULL,	    NULL },
657	{ 0x1c, 0x1f, NULL,	    NULL },
658	{ 0x20, 0xff, NULL,	    NULL },
659
660	{ -1, -1, NULL, NULL }
661};
662
663/* osc_string state table. */
664static const struct input_transition input_state_osc_string_table[] = {
665	INPUT_STATE_ANYWHERE,
666
667	{ 0x00, 0x06, NULL,	     NULL },
668	{ 0x07, 0x07, input_end_bel, &input_state_ground },
669	{ 0x08, 0x17, NULL,	     NULL },
670	{ 0x19, 0x19, NULL,	     NULL },
671	{ 0x1c, 0x1f, NULL,	     NULL },
672	{ 0x20, 0xff, input_input,   NULL },
673
674	{ -1, -1, NULL, NULL }
675};
676
677/* apc_string state table. */
678static const struct input_transition input_state_apc_string_table[] = {
679	INPUT_STATE_ANYWHERE,
680
681	{ 0x00, 0x17, NULL,	    NULL },
682	{ 0x19, 0x19, NULL,	    NULL },
683	{ 0x1c, 0x1f, NULL,	    NULL },
684	{ 0x20, 0xff, input_input,  NULL },
685
686	{ -1, -1, NULL, NULL }
687};
688
689/* rename_string state table. */
690static const struct input_transition input_state_rename_string_table[] = {
691	INPUT_STATE_ANYWHERE,
692
693	{ 0x00, 0x17, NULL,	    NULL },
694	{ 0x19, 0x19, NULL,	    NULL },
695	{ 0x1c, 0x1f, NULL,	    NULL },
696	{ 0x20, 0xff, input_input,  NULL },
697
698	{ -1, -1, NULL, NULL }
699};
700
701/* consume_st state table. */
702static const struct input_transition input_state_consume_st_table[] = {
703	INPUT_STATE_ANYWHERE,
704
705	{ 0x00, 0x17, NULL,	    NULL },
706	{ 0x19, 0x19, NULL,	    NULL },
707	{ 0x1c, 0x1f, NULL,	    NULL },
708	{ 0x20, 0xff, NULL,	    NULL },
709
710	{ -1, -1, NULL, NULL }
711};
712
713/* Input table compare. */
714static int
715input_table_compare(const void *key, const void *value)
716{
717	const struct input_ctx		*ictx = key;
718	const struct input_table_entry	*entry = value;
719
720	if (ictx->ch != entry->ch)
721		return (ictx->ch - entry->ch);
722	return (strcmp(ictx->interm_buf, entry->interm));
723}
724
725/*
726 * Timer - if this expires then have been waiting for a terminator for too
727 * long, so reset to ground.
728 */
729static void
730input_timer_callback(__unused int fd, __unused short events, void *arg)
731{
732	struct input_ctx	*ictx = arg;
733	struct window_pane	*wp = ictx->wp;
734
735	log_debug("%s: %%%u %s expired" , __func__, wp->id, ictx->state->name);
736	input_reset(wp, 0);
737}
738
739/* Start the timer. */
740static void
741input_start_timer(struct input_ctx *ictx)
742{
743	struct timeval	tv = { .tv_usec = 100000 };
744
745	event_del(&ictx->timer);
746	event_add(&ictx->timer, &tv);
747}
748
749/* Reset cell state to default. */
750static void
751input_reset_cell(struct input_ctx *ictx)
752{
753	memcpy(&ictx->cell.cell, &grid_default_cell, sizeof ictx->cell.cell);
754	ictx->cell.set = 0;
755	ictx->cell.g0set = ictx->cell.g1set = 0;
756
757	memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
758	ictx->old_cx = 0;
759	ictx->old_cy = 0;
760}
761
762/* Save screen state. */
763static void
764input_save_state(struct input_ctx *ictx)
765{
766	struct screen_write_ctx	*sctx = &ictx->ctx;
767	struct screen		*s = sctx->s;
768
769	memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
770	ictx->old_cx = s->cx;
771	ictx->old_cy = s->cy;
772	ictx->old_mode = s->mode;
773}
774
775static void
776input_restore_state(struct input_ctx *ictx)
777{
778	struct screen_write_ctx	*sctx = &ictx->ctx;
779
780	memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
781	if (ictx->old_mode & MODE_ORIGIN)
782		screen_write_mode_set(sctx, MODE_ORIGIN);
783	else
784		screen_write_mode_clear(sctx, MODE_ORIGIN);
785	screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy, 0);
786}
787
788/* Initialise input parser. */
789void
790input_init(struct window_pane *wp)
791{
792	struct input_ctx	*ictx;
793
794	ictx = wp->ictx = xcalloc(1, sizeof *ictx);
795
796	ictx->input_space = INPUT_BUF_START;
797	ictx->input_buf = xmalloc(INPUT_BUF_START);
798
799	ictx->since_ground = evbuffer_new();
800	if (ictx->since_ground == NULL)
801		fatalx("out of memory");
802
803	evtimer_set(&ictx->timer, input_timer_callback, ictx);
804
805	input_reset(wp, 0);
806}
807
808/* Destroy input parser. */
809void
810input_free(struct window_pane *wp)
811{
812	struct input_ctx	*ictx = wp->ictx;
813	u_int			 i;
814
815	for (i = 0; i < ictx->param_list_len; i++) {
816		if (ictx->param_list[i].type == INPUT_STRING)
817			free(ictx->param_list[i].str);
818	}
819
820	event_del(&ictx->timer);
821
822	free(ictx->input_buf);
823	evbuffer_free(ictx->since_ground);
824
825	free(ictx);
826	wp->ictx = NULL;
827}
828
829/* Reset input state and clear screen. */
830void
831input_reset(struct window_pane *wp, int clear)
832{
833	struct input_ctx	*ictx = wp->ictx;
834	struct screen_write_ctx	*sctx = &ictx->ctx;
835
836	input_reset_cell(ictx);
837
838	if (clear) {
839		if (TAILQ_EMPTY(&wp->modes))
840			screen_write_start(sctx, wp, &wp->base);
841		else
842			screen_write_start(sctx, NULL, &wp->base);
843		screen_write_reset(sctx);
844		screen_write_stop(sctx);
845	}
846
847	input_clear(ictx);
848
849	ictx->last = -1;
850
851	ictx->state = &input_state_ground;
852	ictx->flags = 0;
853}
854
855/* Return pending data. */
856struct evbuffer *
857input_pending(struct window_pane *wp)
858{
859	return (wp->ictx->since_ground);
860}
861
862/* Change input state. */
863static void
864input_set_state(struct window_pane *wp, const struct input_transition *itr)
865{
866	struct input_ctx	*ictx = wp->ictx;
867
868	if (ictx->state->exit != NULL)
869		ictx->state->exit(ictx);
870	ictx->state = itr->state;
871	if (ictx->state->enter != NULL)
872		ictx->state->enter(ictx);
873}
874
875/* Parse input. */
876void
877input_parse(struct window_pane *wp)
878{
879	struct evbuffer		*evb = wp->event->input;
880
881	input_parse_buffer(wp, EVBUFFER_DATA(evb), EVBUFFER_LENGTH(evb));
882	evbuffer_drain(evb, EVBUFFER_LENGTH(evb));
883}
884
885/* Parse given input. */
886void
887input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
888{
889	struct input_ctx		*ictx = wp->ictx;
890	struct screen_write_ctx		*sctx = &ictx->ctx;
891	const struct input_state	*state = NULL;
892	const struct input_transition	*itr = NULL;
893	size_t				 off = 0;
894
895	if (len == 0)
896		return;
897
898	window_update_activity(wp->window);
899	wp->flags |= PANE_CHANGED;
900	notify_input(wp, buf, len);
901
902	/*
903	 * Open the screen. Use NULL wp if there is a mode set as don't want to
904	 * update the tty.
905	 */
906	if (TAILQ_EMPTY(&wp->modes))
907		screen_write_start(sctx, wp, &wp->base);
908	else
909		screen_write_start(sctx, NULL, &wp->base);
910	ictx->wp = wp;
911
912	log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
913	    ictx->state->name, len, (int)len, buf);
914
915	/* Parse the input. */
916	while (off < len) {
917		ictx->ch = buf[off++];
918
919		/* Find the transition. */
920		if (ictx->state != state ||
921		    itr == NULL ||
922		    ictx->ch < itr->first ||
923		    ictx->ch > itr->last) {
924			itr = ictx->state->transitions;
925			while (itr->first != -1 && itr->last != -1) {
926				if (ictx->ch >= itr->first && ictx->ch <= itr->last)
927					break;
928				itr++;
929			}
930			if (itr->first == -1 || itr->last == -1) {
931				/* No transition? Eh? */
932				fatalx("no transition from state");
933			}
934		}
935		state = ictx->state;
936
937		/*
938		 * Any state except print stops the current collection. This is
939		 * an optimization to avoid checking if the attributes have
940		 * changed for every character. It will stop unnecessarily for
941		 * sequences that don't make a terminal change, but they should
942		 * be the minority.
943		 */
944		if (itr->handler != input_print)
945			screen_write_collect_end(sctx);
946
947		/*
948		 * Execute the handler, if any. Don't switch state if it
949		 * returns non-zero.
950		 */
951		if (itr->handler != NULL && itr->handler(ictx) != 0)
952			continue;
953
954		/* And switch state, if necessary. */
955		if (itr->state != NULL)
956			input_set_state(wp, itr);
957
958		/* If not in ground state, save input. */
959		if (ictx->state != &input_state_ground)
960			evbuffer_add(ictx->since_ground, &ictx->ch, 1);
961	}
962
963	/* Close the screen. */
964	screen_write_stop(sctx);
965}
966
967/* Split the parameter list (if any). */
968static int
969input_split(struct input_ctx *ictx)
970{
971	const char		*errstr;
972	char			*ptr, *out;
973	struct input_param	*ip;
974	u_int			 i;
975
976	for (i = 0; i < ictx->param_list_len; i++) {
977		if (ictx->param_list[i].type == INPUT_STRING)
978			free(ictx->param_list[i].str);
979	}
980	ictx->param_list_len = 0;
981
982	if (ictx->param_len == 0)
983		return (0);
984	ip = &ictx->param_list[0];
985
986	ptr = ictx->param_buf;
987	while ((out = strsep(&ptr, ";")) != NULL) {
988		if (*out == '\0')
989			ip->type = INPUT_MISSING;
990		else {
991			if (strchr(out, ':') != NULL) {
992				ip->type = INPUT_STRING;
993				ip->str = xstrdup(out);
994			} else {
995				ip->type = INPUT_NUMBER;
996				ip->num = strtonum(out, 0, INT_MAX, &errstr);
997				if (errstr != NULL)
998					return (-1);
999			}
1000		}
1001		ip = &ictx->param_list[++ictx->param_list_len];
1002		if (ictx->param_list_len == nitems(ictx->param_list))
1003			return (-1);
1004	}
1005
1006	for (i = 0; i < ictx->param_list_len; i++) {
1007		ip = &ictx->param_list[i];
1008		if (ip->type == INPUT_MISSING)
1009			log_debug("parameter %u: missing", i);
1010		else if (ip->type == INPUT_STRING)
1011			log_debug("parameter %u: string %s", i, ip->str);
1012		else if (ip->type == INPUT_NUMBER)
1013			log_debug("parameter %u: number %d", i, ip->num);
1014	}
1015
1016	return (0);
1017}
1018
1019/* Get an argument or return default value. */
1020static int
1021input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
1022{
1023	struct input_param	*ip;
1024	int			 retval;
1025
1026	if (validx >= ictx->param_list_len)
1027	    return (defval);
1028	ip = &ictx->param_list[validx];
1029	if (ip->type == INPUT_MISSING)
1030		return (defval);
1031	if (ip->type == INPUT_STRING)
1032		return (-1);
1033	retval = ip->num;
1034	if (retval < minval)
1035		return (minval);
1036	return (retval);
1037}
1038
1039/* Reply to terminal query. */
1040static void
1041input_reply(struct input_ctx *ictx, const char *fmt, ...)
1042{
1043	va_list	 ap;
1044	char	*reply;
1045
1046	va_start(ap, fmt);
1047	xvasprintf(&reply, fmt, ap);
1048	va_end(ap);
1049
1050	bufferevent_write(ictx->wp->event, reply, strlen(reply));
1051	free(reply);
1052}
1053
1054/* Clear saved state. */
1055static void
1056input_clear(struct input_ctx *ictx)
1057{
1058	event_del(&ictx->timer);
1059
1060	*ictx->interm_buf = '\0';
1061	ictx->interm_len = 0;
1062
1063	*ictx->param_buf = '\0';
1064	ictx->param_len = 0;
1065
1066	*ictx->input_buf = '\0';
1067	ictx->input_len = 0;
1068
1069	ictx->input_end = INPUT_END_ST;
1070
1071	ictx->flags &= ~INPUT_DISCARD;
1072}
1073
1074/* Reset for ground state. */
1075static void
1076input_ground(struct input_ctx *ictx)
1077{
1078	event_del(&ictx->timer);
1079	evbuffer_drain(ictx->since_ground, EVBUFFER_LENGTH(ictx->since_ground));
1080
1081	if (ictx->input_space > INPUT_BUF_START) {
1082		ictx->input_space = INPUT_BUF_START;
1083		ictx->input_buf = xrealloc(ictx->input_buf, INPUT_BUF_START);
1084	}
1085}
1086
1087/* Output this character to the screen. */
1088static int
1089input_print(struct input_ctx *ictx)
1090{
1091	struct screen_write_ctx	*sctx = &ictx->ctx;
1092	int			 set;
1093
1094	ictx->utf8started = 0; /* can't be valid UTF-8 */
1095
1096	set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
1097	if (set == 1)
1098		ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
1099	else
1100		ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1101
1102	utf8_set(&ictx->cell.cell.data, ictx->ch);
1103	screen_write_collect_add(sctx, &ictx->cell.cell);
1104	ictx->last = ictx->ch;
1105
1106	ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1107
1108	return (0);
1109}
1110
1111/* Collect intermediate string. */
1112static int
1113input_intermediate(struct input_ctx *ictx)
1114{
1115	if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
1116		ictx->flags |= INPUT_DISCARD;
1117	else {
1118		ictx->interm_buf[ictx->interm_len++] = ictx->ch;
1119		ictx->interm_buf[ictx->interm_len] = '\0';
1120	}
1121
1122	return (0);
1123}
1124
1125/* Collect parameter string. */
1126static int
1127input_parameter(struct input_ctx *ictx)
1128{
1129	if (ictx->param_len == (sizeof ictx->param_buf) - 1)
1130		ictx->flags |= INPUT_DISCARD;
1131	else {
1132		ictx->param_buf[ictx->param_len++] = ictx->ch;
1133		ictx->param_buf[ictx->param_len] = '\0';
1134	}
1135
1136	return (0);
1137}
1138
1139/* Collect input string. */
1140static int
1141input_input(struct input_ctx *ictx)
1142{
1143	size_t available;
1144
1145	available = ictx->input_space;
1146	while (ictx->input_len + 1 >= available) {
1147		available *= 2;
1148		if (available > INPUT_BUF_LIMIT) {
1149			ictx->flags |= INPUT_DISCARD;
1150			return (0);
1151		}
1152		ictx->input_buf = xrealloc(ictx->input_buf, available);
1153		ictx->input_space = available;
1154	}
1155	ictx->input_buf[ictx->input_len++] = ictx->ch;
1156	ictx->input_buf[ictx->input_len] = '\0';
1157
1158	return (0);
1159}
1160
1161/* Execute C0 control sequence. */
1162static int
1163input_c0_dispatch(struct input_ctx *ictx)
1164{
1165	struct screen_write_ctx	*sctx = &ictx->ctx;
1166	struct window_pane	*wp = ictx->wp;
1167	struct screen		*s = sctx->s;
1168
1169	ictx->utf8started = 0; /* can't be valid UTF-8 */
1170
1171	log_debug("%s: '%c'", __func__, ictx->ch);
1172
1173	switch (ictx->ch) {
1174	case '\000':	/* NUL */
1175		break;
1176	case '\007':	/* BEL */
1177		alerts_queue(wp->window, WINDOW_BELL);
1178		break;
1179	case '\010':	/* BS */
1180		screen_write_backspace(sctx);
1181		break;
1182	case '\011':	/* HT */
1183		/* Don't tab beyond the end of the line. */
1184		if (s->cx >= screen_size_x(s) - 1)
1185			break;
1186
1187		/* Find the next tab point, or use the last column if none. */
1188		do {
1189			s->cx++;
1190			if (bit_test(s->tabs, s->cx))
1191				break;
1192		} while (s->cx < screen_size_x(s) - 1);
1193		break;
1194	case '\012':	/* LF */
1195	case '\013':	/* VT */
1196	case '\014':	/* FF */
1197		screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1198		if (s->mode & MODE_CRLF)
1199			screen_write_carriagereturn(sctx);
1200		break;
1201	case '\015':	/* CR */
1202		screen_write_carriagereturn(sctx);
1203		break;
1204	case '\016':	/* SO */
1205		ictx->cell.set = 1;
1206		break;
1207	case '\017':	/* SI */
1208		ictx->cell.set = 0;
1209		break;
1210	default:
1211		log_debug("%s: unknown '%c'", __func__, ictx->ch);
1212		break;
1213	}
1214
1215	ictx->last = -1;
1216	return (0);
1217}
1218
1219/* Execute escape sequence. */
1220static int
1221input_esc_dispatch(struct input_ctx *ictx)
1222{
1223	struct screen_write_ctx		*sctx = &ictx->ctx;
1224	struct screen			*s = sctx->s;
1225	struct input_table_entry	*entry;
1226
1227	if (ictx->flags & INPUT_DISCARD)
1228		return (0);
1229	log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1230
1231	entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
1232	    sizeof input_esc_table[0], input_table_compare);
1233	if (entry == NULL) {
1234		log_debug("%s: unknown '%c'", __func__, ictx->ch);
1235		return (0);
1236	}
1237
1238	switch (entry->type) {
1239	case INPUT_ESC_RIS:
1240		window_pane_reset_palette(ictx->wp);
1241		input_reset_cell(ictx);
1242		screen_write_reset(sctx);
1243		break;
1244	case INPUT_ESC_IND:
1245		screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1246		break;
1247	case INPUT_ESC_NEL:
1248		screen_write_carriagereturn(sctx);
1249		screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1250		break;
1251	case INPUT_ESC_HTS:
1252		if (s->cx < screen_size_x(s))
1253			bit_set(s->tabs, s->cx);
1254		break;
1255	case INPUT_ESC_RI:
1256		screen_write_reverseindex(sctx, ictx->cell.cell.bg);
1257		break;
1258	case INPUT_ESC_DECKPAM:
1259		screen_write_mode_set(sctx, MODE_KKEYPAD);
1260		break;
1261	case INPUT_ESC_DECKPNM:
1262		screen_write_mode_clear(sctx, MODE_KKEYPAD);
1263		break;
1264	case INPUT_ESC_DECSC:
1265		input_save_state(ictx);
1266		break;
1267	case INPUT_ESC_DECRC:
1268		input_restore_state(ictx);
1269		break;
1270	case INPUT_ESC_DECALN:
1271		screen_write_alignmenttest(sctx);
1272		break;
1273	case INPUT_ESC_SCSG0_ON:
1274		ictx->cell.g0set = 1;
1275		break;
1276	case INPUT_ESC_SCSG0_OFF:
1277		ictx->cell.g0set = 0;
1278		break;
1279	case INPUT_ESC_SCSG1_ON:
1280		ictx->cell.g1set = 1;
1281		break;
1282	case INPUT_ESC_SCSG1_OFF:
1283		ictx->cell.g1set = 0;
1284		break;
1285	case INPUT_ESC_ST:
1286		/* ST terminates OSC but the state transition already did it. */
1287		break;
1288	}
1289
1290	ictx->last = -1;
1291	return (0);
1292}
1293
1294/* Execute control sequence. */
1295static int
1296input_csi_dispatch(struct input_ctx *ictx)
1297{
1298	struct screen_write_ctx	       *sctx = &ictx->ctx;
1299	struct screen		       *s = sctx->s;
1300	struct input_table_entry       *entry;
1301	int				i, n, m;
1302	u_int				cx, bg = ictx->cell.cell.bg;
1303
1304	if (ictx->flags & INPUT_DISCARD)
1305		return (0);
1306
1307	log_debug("%s: '%c' \"%s\" \"%s\"",
1308	    __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1309
1310	if (input_split(ictx) != 0)
1311		return (0);
1312
1313	entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1314	    sizeof input_csi_table[0], input_table_compare);
1315	if (entry == NULL) {
1316		log_debug("%s: unknown '%c'", __func__, ictx->ch);
1317		return (0);
1318	}
1319
1320	switch (entry->type) {
1321	case INPUT_CSI_CBT:
1322		/* Find the previous tab point, n times. */
1323		cx = s->cx;
1324		if (cx > screen_size_x(s) - 1)
1325			cx = screen_size_x(s) - 1;
1326		n = input_get(ictx, 0, 1, 1);
1327		if (n == -1)
1328			break;
1329		while (cx > 0 && n-- > 0) {
1330			do
1331				cx--;
1332			while (cx > 0 && !bit_test(s->tabs, cx));
1333		}
1334		s->cx = cx;
1335		break;
1336	case INPUT_CSI_CUB:
1337		n = input_get(ictx, 0, 1, 1);
1338		if (n != -1)
1339			screen_write_cursorleft(sctx, n);
1340		break;
1341	case INPUT_CSI_CUD:
1342		n = input_get(ictx, 0, 1, 1);
1343		if (n != -1)
1344			screen_write_cursordown(sctx, n);
1345		break;
1346	case INPUT_CSI_CUF:
1347		n = input_get(ictx, 0, 1, 1);
1348		if (n != -1)
1349			screen_write_cursorright(sctx, n);
1350		break;
1351	case INPUT_CSI_CUP:
1352		n = input_get(ictx, 0, 1, 1);
1353		m = input_get(ictx, 1, 1, 1);
1354		if (n != -1 && m != -1)
1355			screen_write_cursormove(sctx, m - 1, n - 1, 1);
1356		break;
1357	case INPUT_CSI_WINOPS:
1358		input_csi_dispatch_winops(ictx);
1359		break;
1360	case INPUT_CSI_CUU:
1361		n = input_get(ictx, 0, 1, 1);
1362		if (n != -1)
1363			screen_write_cursorup(sctx, n);
1364		break;
1365	case INPUT_CSI_CNL:
1366		n = input_get(ictx, 0, 1, 1);
1367		if (n != -1) {
1368			screen_write_carriagereturn(sctx);
1369			screen_write_cursordown(sctx, n);
1370		}
1371		break;
1372	case INPUT_CSI_CPL:
1373		n = input_get(ictx, 0, 1, 1);
1374		if (n != -1) {
1375			screen_write_carriagereturn(sctx);
1376			screen_write_cursorup(sctx, n);
1377		}
1378		break;
1379	case INPUT_CSI_DA:
1380		switch (input_get(ictx, 0, 0, 0)) {
1381		case -1:
1382			break;
1383		case 0:
1384			input_reply(ictx, "\033[?1;2c");
1385			break;
1386		default:
1387			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1388			break;
1389		}
1390		break;
1391	case INPUT_CSI_DA_TWO:
1392		switch (input_get(ictx, 0, 0, 0)) {
1393		case -1:
1394			break;
1395		case 0:
1396			input_reply(ictx, "\033[>84;0;0c");
1397			break;
1398		default:
1399			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1400			break;
1401		}
1402		break;
1403	case INPUT_CSI_ECH:
1404		n = input_get(ictx, 0, 1, 1);
1405		if (n != -1)
1406			screen_write_clearcharacter(sctx, n, bg);
1407		break;
1408	case INPUT_CSI_DCH:
1409		n = input_get(ictx, 0, 1, 1);
1410		if (n != -1)
1411			screen_write_deletecharacter(sctx, n, bg);
1412		break;
1413	case INPUT_CSI_DECSTBM:
1414		n = input_get(ictx, 0, 1, 1);
1415		m = input_get(ictx, 1, 1, screen_size_y(s));
1416		if (n != -1 && m != -1)
1417			screen_write_scrollregion(sctx, n - 1, m - 1);
1418		break;
1419	case INPUT_CSI_DL:
1420		n = input_get(ictx, 0, 1, 1);
1421		if (n != -1)
1422			screen_write_deleteline(sctx, n, bg);
1423		break;
1424	case INPUT_CSI_DSR:
1425		switch (input_get(ictx, 0, 0, 0)) {
1426		case -1:
1427			break;
1428		case 5:
1429			input_reply(ictx, "\033[0n");
1430			break;
1431		case 6:
1432			input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1433			break;
1434		default:
1435			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1436			break;
1437		}
1438		break;
1439	case INPUT_CSI_ED:
1440		switch (input_get(ictx, 0, 0, 0)) {
1441		case -1:
1442			break;
1443		case 0:
1444			screen_write_clearendofscreen(sctx, bg);
1445			break;
1446		case 1:
1447			screen_write_clearstartofscreen(sctx, bg);
1448			break;
1449		case 2:
1450			screen_write_clearscreen(sctx, bg);
1451			break;
1452		case 3:
1453			if (input_get(ictx, 1, 0, 0) == 0) {
1454				/*
1455				 * Linux console extension to clear history
1456				 * (for example before locking the screen).
1457				 */
1458				screen_write_clearhistory(sctx);
1459			}
1460			break;
1461		default:
1462			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1463			break;
1464		}
1465		break;
1466	case INPUT_CSI_EL:
1467		switch (input_get(ictx, 0, 0, 0)) {
1468		case -1:
1469			break;
1470		case 0:
1471			screen_write_clearendofline(sctx, bg);
1472			break;
1473		case 1:
1474			screen_write_clearstartofline(sctx, bg);
1475			break;
1476		case 2:
1477			screen_write_clearline(sctx, bg);
1478			break;
1479		default:
1480			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1481			break;
1482		}
1483		break;
1484	case INPUT_CSI_HPA:
1485		n = input_get(ictx, 0, 1, 1);
1486		if (n != -1)
1487			screen_write_cursormove(sctx, n - 1, -1, 1);
1488		break;
1489	case INPUT_CSI_ICH:
1490		n = input_get(ictx, 0, 1, 1);
1491		if (n != -1)
1492			screen_write_insertcharacter(sctx, n, bg);
1493		break;
1494	case INPUT_CSI_IL:
1495		n = input_get(ictx, 0, 1, 1);
1496		if (n != -1)
1497			screen_write_insertline(sctx, n, bg);
1498		break;
1499	case INPUT_CSI_REP:
1500		n = input_get(ictx, 0, 1, 1);
1501		if (n == -1)
1502			break;
1503
1504		if (ictx->last == -1)
1505			break;
1506		ictx->ch = ictx->last;
1507
1508		for (i = 0; i < n; i++)
1509			input_print(ictx);
1510		break;
1511	case INPUT_CSI_RCP:
1512		input_restore_state(ictx);
1513		break;
1514	case INPUT_CSI_RM:
1515		input_csi_dispatch_rm(ictx);
1516		break;
1517	case INPUT_CSI_RM_PRIVATE:
1518		input_csi_dispatch_rm_private(ictx);
1519		break;
1520	case INPUT_CSI_SCP:
1521		input_save_state(ictx);
1522		break;
1523	case INPUT_CSI_SGR:
1524		input_csi_dispatch_sgr(ictx);
1525		break;
1526	case INPUT_CSI_SM:
1527		input_csi_dispatch_sm(ictx);
1528		break;
1529	case INPUT_CSI_SM_PRIVATE:
1530		input_csi_dispatch_sm_private(ictx);
1531		break;
1532	case INPUT_CSI_SU:
1533		n = input_get(ictx, 0, 1, 1);
1534		if (n != -1)
1535			screen_write_scrollup(sctx, n, bg);
1536		break;
1537	case INPUT_CSI_SD:
1538		n = input_get(ictx, 0, 1, 1);
1539		if (n != -1)
1540			screen_write_scrolldown(sctx, n, bg);
1541		break;
1542	case INPUT_CSI_TBC:
1543		switch (input_get(ictx, 0, 0, 0)) {
1544		case -1:
1545			break;
1546		case 0:
1547			if (s->cx < screen_size_x(s))
1548				bit_clear(s->tabs, s->cx);
1549			break;
1550		case 3:
1551			bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1552			break;
1553		default:
1554			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1555			break;
1556		}
1557		break;
1558	case INPUT_CSI_VPA:
1559		n = input_get(ictx, 0, 1, 1);
1560		if (n != -1)
1561			screen_write_cursormove(sctx, -1, n - 1, 1);
1562		break;
1563	case INPUT_CSI_DECSCUSR:
1564		n = input_get(ictx, 0, 0, 0);
1565		if (n != -1)
1566			screen_set_cursor_style(s, n);
1567		break;
1568	}
1569
1570	ictx->last = -1;
1571	return (0);
1572}
1573
1574/* Handle CSI RM. */
1575static void
1576input_csi_dispatch_rm(struct input_ctx *ictx)
1577{
1578	struct screen_write_ctx	*sctx = &ictx->ctx;
1579	u_int			 i;
1580
1581	for (i = 0; i < ictx->param_list_len; i++) {
1582		switch (input_get(ictx, i, 0, -1)) {
1583		case -1:
1584			break;
1585		case 4:		/* IRM */
1586			screen_write_mode_clear(sctx, MODE_INSERT);
1587			break;
1588		case 34:
1589			screen_write_mode_set(sctx, MODE_BLINKING);
1590			break;
1591		default:
1592			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1593			break;
1594		}
1595	}
1596}
1597
1598/* Handle CSI private RM. */
1599static void
1600input_csi_dispatch_rm_private(struct input_ctx *ictx)
1601{
1602	struct screen_write_ctx	*sctx = &ictx->ctx;
1603	struct window_pane	*wp = ictx->wp;
1604	u_int			 i;
1605
1606	for (i = 0; i < ictx->param_list_len; i++) {
1607		switch (input_get(ictx, i, 0, -1)) {
1608		case -1:
1609			break;
1610		case 1:		/* DECCKM */
1611			screen_write_mode_clear(sctx, MODE_KCURSOR);
1612			break;
1613		case 3:		/* DECCOLM */
1614			screen_write_cursormove(sctx, 0, 0, 1);
1615			screen_write_clearscreen(sctx, ictx->cell.cell.bg);
1616			break;
1617		case 6:		/* DECOM */
1618			screen_write_mode_clear(sctx, MODE_ORIGIN);
1619			screen_write_cursormove(sctx, 0, 0, 1);
1620			break;
1621		case 7:		/* DECAWM */
1622			screen_write_mode_clear(sctx, MODE_WRAP);
1623			break;
1624		case 12:
1625			screen_write_mode_clear(sctx, MODE_BLINKING);
1626			break;
1627		case 25:	/* TCEM */
1628			screen_write_mode_clear(sctx, MODE_CURSOR);
1629			break;
1630		case 1000:
1631		case 1001:
1632		case 1002:
1633		case 1003:
1634			screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1635			break;
1636		case 1004:
1637			screen_write_mode_clear(sctx, MODE_FOCUSON);
1638			break;
1639		case 1005:
1640			screen_write_mode_clear(sctx, MODE_MOUSE_UTF8);
1641			break;
1642		case 1006:
1643			screen_write_mode_clear(sctx, MODE_MOUSE_SGR);
1644			break;
1645		case 47:
1646		case 1047:
1647			window_pane_alternate_off(wp, &ictx->cell.cell, 0);
1648			break;
1649		case 1049:
1650			window_pane_alternate_off(wp, &ictx->cell.cell, 1);
1651			break;
1652		case 2004:
1653			screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
1654			break;
1655		default:
1656			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1657			break;
1658		}
1659	}
1660}
1661
1662/* Handle CSI SM. */
1663static void
1664input_csi_dispatch_sm(struct input_ctx *ictx)
1665{
1666	struct screen_write_ctx	*sctx = &ictx->ctx;
1667	u_int			 i;
1668
1669	for (i = 0; i < ictx->param_list_len; i++) {
1670		switch (input_get(ictx, i, 0, -1)) {
1671		case -1:
1672			break;
1673		case 4:		/* IRM */
1674			screen_write_mode_set(sctx, MODE_INSERT);
1675			break;
1676		case 34:
1677			screen_write_mode_clear(sctx, MODE_BLINKING);
1678			break;
1679		default:
1680			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1681			break;
1682		}
1683	}
1684}
1685
1686/* Handle CSI private SM. */
1687static void
1688input_csi_dispatch_sm_private(struct input_ctx *ictx)
1689{
1690	struct screen_write_ctx	*sctx = &ictx->ctx;
1691	struct window_pane	*wp = ictx->wp;
1692	u_int			 i;
1693
1694	for (i = 0; i < ictx->param_list_len; i++) {
1695		switch (input_get(ictx, i, 0, -1)) {
1696		case -1:
1697			break;
1698		case 1:		/* DECCKM */
1699			screen_write_mode_set(sctx, MODE_KCURSOR);
1700			break;
1701		case 3:		/* DECCOLM */
1702			screen_write_cursormove(sctx, 0, 0, 1);
1703			screen_write_clearscreen(sctx, ictx->cell.cell.bg);
1704			break;
1705		case 6:		/* DECOM */
1706			screen_write_mode_set(sctx, MODE_ORIGIN);
1707			screen_write_cursormove(sctx, 0, 0, 1);
1708			break;
1709		case 7:		/* DECAWM */
1710			screen_write_mode_set(sctx, MODE_WRAP);
1711			break;
1712		case 12:
1713			screen_write_mode_set(sctx, MODE_BLINKING);
1714			break;
1715		case 25:	/* TCEM */
1716			screen_write_mode_set(sctx, MODE_CURSOR);
1717			break;
1718		case 1000:
1719			screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1720			screen_write_mode_set(sctx, MODE_MOUSE_STANDARD);
1721			break;
1722		case 1002:
1723			screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1724			screen_write_mode_set(sctx, MODE_MOUSE_BUTTON);
1725			break;
1726		case 1003:
1727			screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1728			screen_write_mode_set(sctx, MODE_MOUSE_ALL);
1729			break;
1730		case 1004:
1731			if (sctx->s->mode & MODE_FOCUSON)
1732				break;
1733			screen_write_mode_set(sctx, MODE_FOCUSON);
1734			wp->flags |= PANE_FOCUSPUSH; /* force update */
1735			break;
1736		case 1005:
1737			screen_write_mode_set(sctx, MODE_MOUSE_UTF8);
1738			break;
1739		case 1006:
1740			screen_write_mode_set(sctx, MODE_MOUSE_SGR);
1741			break;
1742		case 47:
1743		case 1047:
1744			window_pane_alternate_on(wp, &ictx->cell.cell, 0);
1745			break;
1746		case 1049:
1747			window_pane_alternate_on(wp, &ictx->cell.cell, 1);
1748			break;
1749		case 2004:
1750			screen_write_mode_set(sctx, MODE_BRACKETPASTE);
1751			break;
1752		default:
1753			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1754			break;
1755		}
1756	}
1757}
1758
1759/* Handle CSI window operations. */
1760static void
1761input_csi_dispatch_winops(struct input_ctx *ictx)
1762{
1763	struct screen_write_ctx	*sctx = &ictx->ctx;
1764	struct window_pane	*wp = ictx->wp;
1765	int			 n, m;
1766
1767	m = 0;
1768	while ((n = input_get(ictx, m, 0, -1)) != -1) {
1769		switch (n) {
1770		case 1:
1771		case 2:
1772		case 5:
1773		case 6:
1774		case 7:
1775		case 11:
1776		case 13:
1777		case 14:
1778		case 19:
1779		case 20:
1780		case 21:
1781		case 24:
1782			break;
1783		case 3:
1784		case 4:
1785		case 8:
1786			m++;
1787			if (input_get(ictx, m, 0, -1) == -1)
1788				return;
1789			/* FALLTHROUGH */
1790		case 9:
1791		case 10:
1792			m++;
1793			if (input_get(ictx, m, 0, -1) == -1)
1794				return;
1795			break;
1796		case 22:
1797			m++;
1798			switch (input_get(ictx, m, 0, -1)) {
1799			case -1:
1800				return;
1801			case 0:
1802			case 2:
1803				screen_push_title(sctx->s);
1804				break;
1805			}
1806			break;
1807		case 23:
1808			m++;
1809			switch (input_get(ictx, m, 0, -1)) {
1810			case -1:
1811				return;
1812			case 0:
1813			case 2:
1814				screen_pop_title(sctx->s);
1815				server_status_window(ictx->wp->window);
1816				break;
1817			}
1818			break;
1819		case 18:
1820			input_reply(ictx, "\033[8;%u;%ut", wp->sy, wp->sx);
1821			break;
1822		default:
1823			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1824			break;
1825		}
1826		m++;
1827	}
1828}
1829
1830/* Helper for 256 colour SGR. */
1831static int
1832input_csi_dispatch_sgr_256_do(struct input_ctx *ictx, int fgbg, int c)
1833{
1834	struct grid_cell	*gc = &ictx->cell.cell;
1835
1836	if (c == -1 || c > 255) {
1837		if (fgbg == 38)
1838			gc->fg = 8;
1839		else if (fgbg == 48)
1840			gc->bg = 8;
1841	} else {
1842		if (fgbg == 38)
1843			gc->fg = c | COLOUR_FLAG_256;
1844		else if (fgbg == 48)
1845			gc->bg = c | COLOUR_FLAG_256;
1846		else if (fgbg == 58)
1847			gc->us = c | COLOUR_FLAG_256;
1848	}
1849	return (1);
1850}
1851
1852/* Handle CSI SGR for 256 colours. */
1853static void
1854input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
1855{
1856	int	c;
1857
1858	c = input_get(ictx, (*i) + 1, 0, -1);
1859	if (input_csi_dispatch_sgr_256_do(ictx, fgbg, c))
1860		(*i)++;
1861}
1862
1863/* Helper for RGB colour SGR. */
1864static int
1865input_csi_dispatch_sgr_rgb_do(struct input_ctx *ictx, int fgbg, int r, int g,
1866    int b)
1867{
1868	struct grid_cell	*gc = &ictx->cell.cell;
1869
1870	if (r == -1 || r > 255)
1871		return (0);
1872	if (g == -1 || g > 255)
1873		return (0);
1874	if (b == -1 || b > 255)
1875		return (0);
1876
1877	if (fgbg == 38)
1878		gc->fg = colour_join_rgb(r, g, b);
1879	else if (fgbg == 48)
1880		gc->bg = colour_join_rgb(r, g, b);
1881	else if (fgbg == 58)
1882		gc->us = colour_join_rgb(r, g, b);
1883	return (1);
1884}
1885
1886/* Handle CSI SGR for RGB colours. */
1887static void
1888input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
1889{
1890	int	r, g, b;
1891
1892	r = input_get(ictx, (*i) + 1, 0, -1);
1893	g = input_get(ictx, (*i) + 2, 0, -1);
1894	b = input_get(ictx, (*i) + 3, 0, -1);
1895	if (input_csi_dispatch_sgr_rgb_do(ictx, fgbg, r, g, b))
1896		(*i) += 3;
1897}
1898
1899/* Handle CSI SGR with a ISO parameter. */
1900static void
1901input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
1902{
1903	struct grid_cell	*gc = &ictx->cell.cell;
1904	char			*s = ictx->param_list[i].str, *copy, *ptr, *out;
1905	int			 p[8];
1906	u_int			 n;
1907	const char		*errstr;
1908
1909	for (n = 0; n < nitems(p); n++)
1910		p[n] = -1;
1911	n = 0;
1912
1913	ptr = copy = xstrdup(s);
1914	while ((out = strsep(&ptr, ":")) != NULL) {
1915		if (*out != '\0') {
1916			p[n++] = strtonum(out, 0, INT_MAX, &errstr);
1917			if (errstr != NULL || n == nitems(p)) {
1918				free(copy);
1919				return;
1920			}
1921		} else
1922			n++;
1923		log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]);
1924	}
1925	free(copy);
1926
1927	if (n == 0)
1928		return;
1929	if (p[0] == 4) {
1930		if (n != 2)
1931			return;
1932		switch (p[1]) {
1933		case 0:
1934			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1935			break;
1936		case 1:
1937			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1938			gc->attr |= GRID_ATTR_UNDERSCORE;
1939			break;
1940		case 2:
1941			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1942			gc->attr |= GRID_ATTR_UNDERSCORE_2;
1943			break;
1944		case 3:
1945			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1946			gc->attr |= GRID_ATTR_UNDERSCORE_3;
1947			break;
1948		case 4:
1949			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1950			gc->attr |= GRID_ATTR_UNDERSCORE_4;
1951			break;
1952		case 5:
1953			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
1954			gc->attr |= GRID_ATTR_UNDERSCORE_5;
1955			break;
1956		}
1957		return;
1958	}
1959	if (n < 2 || (p[0] != 38 && p[0] != 48 && p[0] != 58))
1960		return;
1961	switch (p[1]) {
1962	case 2:
1963		if (n < 3)
1964			break;
1965		if (n == 5)
1966			i = 2;
1967		else
1968			i = 3;
1969		if (n < i + 3)
1970			break;
1971		input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i], p[i + 1],
1972		    p[i + 2]);
1973		break;
1974	case 5:
1975		if (n < 3)
1976			break;
1977		input_csi_dispatch_sgr_256_do(ictx, p[0], p[2]);
1978		break;
1979	}
1980}
1981
1982/* Handle CSI SGR. */
1983static void
1984input_csi_dispatch_sgr(struct input_ctx *ictx)
1985{
1986	struct grid_cell	*gc = &ictx->cell.cell;
1987	u_int			 i;
1988	int			 n;
1989
1990	if (ictx->param_list_len == 0) {
1991		memcpy(gc, &grid_default_cell, sizeof *gc);
1992		return;
1993	}
1994
1995	for (i = 0; i < ictx->param_list_len; i++) {
1996		if (ictx->param_list[i].type == INPUT_STRING) {
1997			input_csi_dispatch_sgr_colon(ictx, i);
1998			continue;
1999		}
2000		n = input_get(ictx, i, 0, 0);
2001		if (n == -1)
2002			continue;
2003
2004		if (n == 38 || n == 48 || n == 58) {
2005			i++;
2006			switch (input_get(ictx, i, 0, -1)) {
2007			case 2:
2008				input_csi_dispatch_sgr_rgb(ictx, n, &i);
2009				break;
2010			case 5:
2011				input_csi_dispatch_sgr_256(ictx, n, &i);
2012				break;
2013			}
2014			continue;
2015		}
2016
2017		switch (n) {
2018		case 0:
2019			memcpy(gc, &grid_default_cell, sizeof *gc);
2020			break;
2021		case 1:
2022			gc->attr |= GRID_ATTR_BRIGHT;
2023			break;
2024		case 2:
2025			gc->attr |= GRID_ATTR_DIM;
2026			break;
2027		case 3:
2028			gc->attr |= GRID_ATTR_ITALICS;
2029			break;
2030		case 4:
2031			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2032			gc->attr |= GRID_ATTR_UNDERSCORE;
2033			break;
2034		case 5:
2035			gc->attr |= GRID_ATTR_BLINK;
2036			break;
2037		case 7:
2038			gc->attr |= GRID_ATTR_REVERSE;
2039			break;
2040		case 8:
2041			gc->attr |= GRID_ATTR_HIDDEN;
2042			break;
2043		case 9:
2044			gc->attr |= GRID_ATTR_STRIKETHROUGH;
2045			break;
2046		case 22:
2047			gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
2048			break;
2049		case 23:
2050			gc->attr &= ~GRID_ATTR_ITALICS;
2051			break;
2052		case 24:
2053			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2054			break;
2055		case 25:
2056			gc->attr &= ~GRID_ATTR_BLINK;
2057			break;
2058		case 27:
2059			gc->attr &= ~GRID_ATTR_REVERSE;
2060			break;
2061		case 28:
2062			gc->attr &= ~GRID_ATTR_HIDDEN;
2063			break;
2064		case 29:
2065			gc->attr &= ~GRID_ATTR_STRIKETHROUGH;
2066			break;
2067		case 30:
2068		case 31:
2069		case 32:
2070		case 33:
2071		case 34:
2072		case 35:
2073		case 36:
2074		case 37:
2075			gc->fg = n - 30;
2076			break;
2077		case 39:
2078			gc->fg = 8;
2079			break;
2080		case 40:
2081		case 41:
2082		case 42:
2083		case 43:
2084		case 44:
2085		case 45:
2086		case 46:
2087		case 47:
2088			gc->bg = n - 40;
2089			break;
2090		case 49:
2091			gc->bg = 8;
2092			break;
2093		case 53:
2094			gc->attr |= GRID_ATTR_OVERLINE;
2095			break;
2096		case 55:
2097			gc->attr &= ~GRID_ATTR_OVERLINE;
2098			break;
2099		case 59:
2100			gc->us = 0;
2101			break;
2102		case 90:
2103		case 91:
2104		case 92:
2105		case 93:
2106		case 94:
2107		case 95:
2108		case 96:
2109		case 97:
2110			gc->fg = n;
2111			break;
2112		case 100:
2113		case 101:
2114		case 102:
2115		case 103:
2116		case 104:
2117		case 105:
2118		case 106:
2119		case 107:
2120			gc->bg = n - 10;
2121			break;
2122		}
2123	}
2124}
2125
2126/* End of input with BEL. */
2127static int
2128input_end_bel(struct input_ctx *ictx)
2129{
2130	log_debug("%s", __func__);
2131
2132	ictx->input_end = INPUT_END_BEL;
2133
2134	return (0);
2135}
2136
2137/* DCS string started. */
2138static void
2139input_enter_dcs(struct input_ctx *ictx)
2140{
2141	log_debug("%s", __func__);
2142
2143	input_clear(ictx);
2144	input_start_timer(ictx);
2145	ictx->last = -1;
2146}
2147
2148/* DCS terminator (ST) received. */
2149static int
2150input_dcs_dispatch(struct input_ctx *ictx)
2151{
2152	struct screen_write_ctx	*sctx = &ictx->ctx;
2153	u_char			*buf = ictx->input_buf;
2154	size_t			 len = ictx->input_len;
2155	const char		 prefix[] = "tmux;";
2156	const u_int		 prefixlen = (sizeof prefix) - 1;
2157
2158	if (ictx->flags & INPUT_DISCARD)
2159		return (0);
2160
2161	log_debug("%s: \"%s\"", __func__, buf);
2162
2163	if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0)
2164		screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen);
2165
2166	return (0);
2167}
2168
2169/* OSC string started. */
2170static void
2171input_enter_osc(struct input_ctx *ictx)
2172{
2173	log_debug("%s", __func__);
2174
2175	input_clear(ictx);
2176	input_start_timer(ictx);
2177	ictx->last = -1;
2178}
2179
2180/* OSC terminator (ST) received. */
2181static void
2182input_exit_osc(struct input_ctx *ictx)
2183{
2184	struct screen_write_ctx	*sctx = &ictx->ctx;
2185	u_char			*p = ictx->input_buf;
2186	u_int			 option;
2187
2188	if (ictx->flags & INPUT_DISCARD)
2189		return;
2190	if (ictx->input_len < 1 || *p < '0' || *p > '9')
2191		return;
2192
2193	log_debug("%s: \"%s\" (end %s)", __func__, p,
2194	    ictx->input_end == INPUT_END_ST ? "ST" : "BEL");
2195
2196	option = 0;
2197	while (*p >= '0' && *p <= '9')
2198		option = option * 10 + *p++ - '0';
2199	if (*p == ';')
2200		p++;
2201
2202	switch (option) {
2203	case 0:
2204	case 2:
2205		if (utf8_isvalid(p)) {
2206			screen_set_title(sctx->s, p);
2207			server_status_window(ictx->wp->window);
2208		}
2209		break;
2210	case 4:
2211		input_osc_4(ictx, p);
2212		break;
2213	case 10:
2214		input_osc_10(ictx, p);
2215		break;
2216	case 11:
2217		input_osc_11(ictx, p);
2218		break;
2219	case 12:
2220		if (utf8_isvalid(p) && *p != '?') /* ? is colour request */
2221			screen_set_cursor_colour(sctx->s, p);
2222		break;
2223	case 52:
2224		input_osc_52(ictx, p);
2225		break;
2226	case 104:
2227		input_osc_104(ictx, p);
2228		break;
2229	case 112:
2230		if (*p == '\0') /* no arguments allowed */
2231			screen_set_cursor_colour(sctx->s, "");
2232		break;
2233	default:
2234		log_debug("%s: unknown '%u'", __func__, option);
2235		break;
2236	}
2237}
2238
2239/* APC string started. */
2240static void
2241input_enter_apc(struct input_ctx *ictx)
2242{
2243	log_debug("%s", __func__);
2244
2245	input_clear(ictx);
2246	input_start_timer(ictx);
2247	ictx->last = -1;
2248}
2249
2250/* APC terminator (ST) received. */
2251static void
2252input_exit_apc(struct input_ctx *ictx)
2253{
2254	struct screen_write_ctx	*sctx = &ictx->ctx;
2255
2256	if (ictx->flags & INPUT_DISCARD)
2257		return;
2258	log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2259
2260	if (!utf8_isvalid(ictx->input_buf))
2261		return;
2262	screen_set_title(sctx->s, ictx->input_buf);
2263	server_status_window(ictx->wp->window);
2264}
2265
2266/* Rename string started. */
2267static void
2268input_enter_rename(struct input_ctx *ictx)
2269{
2270	log_debug("%s", __func__);
2271
2272	input_clear(ictx);
2273	input_start_timer(ictx);
2274	ictx->last = -1;
2275}
2276
2277/* Rename terminator (ST) received. */
2278static void
2279input_exit_rename(struct input_ctx *ictx)
2280{
2281	if (ictx->flags & INPUT_DISCARD)
2282		return;
2283	if (!options_get_number(ictx->wp->options, "allow-rename"))
2284		return;
2285	log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2286
2287	if (!utf8_isvalid(ictx->input_buf))
2288		return;
2289	window_set_name(ictx->wp->window, ictx->input_buf);
2290	options_set_number(ictx->wp->window->options, "automatic-rename", 0);
2291	server_status_window(ictx->wp->window);
2292}
2293
2294/* Open UTF-8 character. */
2295static int
2296input_top_bit_set(struct input_ctx *ictx)
2297{
2298	struct screen_write_ctx	*sctx = &ictx->ctx;
2299	struct utf8_data	*ud = &ictx->utf8data;
2300
2301	ictx->last = -1;
2302
2303	if (!ictx->utf8started) {
2304		if (utf8_open(ud, ictx->ch) != UTF8_MORE)
2305			return (0);
2306		ictx->utf8started = 1;
2307		return (0);
2308	}
2309
2310	switch (utf8_append(ud, ictx->ch)) {
2311	case UTF8_MORE:
2312		return (0);
2313	case UTF8_ERROR:
2314		ictx->utf8started = 0;
2315		return (0);
2316	case UTF8_DONE:
2317		break;
2318	}
2319	ictx->utf8started = 0;
2320
2321	log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size,
2322	    (int)ud->size, ud->data, ud->width);
2323
2324	utf8_copy(&ictx->cell.cell.data, ud);
2325	screen_write_collect_add(sctx, &ictx->cell.cell);
2326
2327	return (0);
2328}
2329
2330/* Handle the OSC 4 sequence for setting (multiple) palette entries. */
2331static void
2332input_osc_4(struct input_ctx *ictx, const char *p)
2333{
2334	struct window_pane	*wp = ictx->wp;
2335	char			*copy, *s, *next = NULL;
2336	long	 		 idx;
2337	u_int			 r, g, b;
2338
2339	copy = s = xstrdup(p);
2340	while (s != NULL && *s != '\0') {
2341		idx = strtol(s, &next, 10);
2342		if (*next++ != ';')
2343			goto bad;
2344		if (idx < 0 || idx >= 0x100)
2345			goto bad;
2346
2347		s = strsep(&next, ";");
2348		if (sscanf(s, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) {
2349			s = next;
2350			continue;
2351		}
2352
2353		window_pane_set_palette(wp, idx, colour_join_rgb(r, g, b));
2354		s = next;
2355	}
2356
2357	free(copy);
2358	return;
2359
2360bad:
2361	log_debug("bad OSC 4: %s", p);
2362	free(copy);
2363}
2364
2365/* Handle the OSC 10 sequence for setting foreground colour. */
2366static void
2367input_osc_10(struct input_ctx *ictx, const char *p)
2368{
2369	struct window_pane	*wp = ictx->wp;
2370	u_int			 r, g, b;
2371	char			 tmp[16];
2372
2373	if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3)
2374	    goto bad;
2375	xsnprintf(tmp, sizeof tmp, "fg=#%02x%02x%02x", r, g, b);
2376	options_set_style(wp->options, "window-style", 1, tmp);
2377	options_set_style(wp->options, "window-active-style", 1, tmp);
2378	wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
2379
2380	return;
2381
2382bad:
2383	log_debug("bad OSC 10: %s", p);
2384}
2385
2386/* Handle the OSC 11 sequence for setting background colour. */
2387static void
2388input_osc_11(struct input_ctx *ictx, const char *p)
2389{
2390	struct window_pane	*wp = ictx->wp;
2391	u_int			 r, g, b;
2392	char			 tmp[16];
2393
2394	if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3)
2395	    goto bad;
2396	xsnprintf(tmp, sizeof tmp, "bg=#%02x%02x%02x", r, g, b);
2397	options_set_style(wp->options, "window-style", 1, tmp);
2398	options_set_style(wp->options, "window-active-style", 1, tmp);
2399	wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
2400
2401	return;
2402
2403bad:
2404	log_debug("bad OSC 11: %s", p);
2405}
2406
2407/* Handle the OSC 52 sequence for setting the clipboard. */
2408static void
2409input_osc_52(struct input_ctx *ictx, const char *p)
2410{
2411	struct window_pane	*wp = ictx->wp;
2412	char			*end;
2413	const char		*buf;
2414	size_t			 len;
2415	u_char			*out;
2416	int			 outlen, state;
2417	struct screen_write_ctx	 ctx;
2418	struct paste_buffer	*pb;
2419
2420	state = options_get_number(global_options, "set-clipboard");
2421	if (state != 2)
2422		return;
2423
2424	if ((end = strchr(p, ';')) == NULL)
2425		return;
2426	end++;
2427	if (*end == '\0')
2428		return;
2429	log_debug("%s: %s", __func__, end);
2430
2431	if (strcmp(end, "?") == 0) {
2432		if ((pb = paste_get_top(NULL)) != NULL) {
2433			buf = paste_buffer_data(pb, &len);
2434			outlen = 4 * ((len + 2) / 3) + 1;
2435			out = xmalloc(outlen);
2436			if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) {
2437				free(out);
2438				return;
2439			}
2440		} else {
2441			outlen = 0;
2442			out = NULL;
2443		}
2444		bufferevent_write(wp->event, "\033]52;;", 6);
2445		if (outlen != 0)
2446			bufferevent_write(wp->event, out, outlen);
2447		if (ictx->input_end == INPUT_END_BEL)
2448			bufferevent_write(wp->event, "\007", 1);
2449		else
2450			bufferevent_write(wp->event, "\033\\", 2);
2451		free(out);
2452		return;
2453	}
2454
2455	len = (strlen(end) / 4) * 3;
2456	if (len == 0)
2457		return;
2458
2459	out = xmalloc(len);
2460	if ((outlen = b64_pton(end, out, len)) == -1) {
2461		free(out);
2462		return;
2463	}
2464
2465	screen_write_start(&ctx, wp, NULL);
2466	screen_write_setselection(&ctx, out, outlen);
2467	screen_write_stop(&ctx);
2468	notify_pane("pane-set-clipboard", wp);
2469
2470	paste_add(NULL, out, outlen);
2471}
2472
2473/* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
2474static void
2475input_osc_104(struct input_ctx *ictx, const char *p)
2476{
2477	struct window_pane	*wp = ictx->wp;
2478	char			*copy, *s;
2479	long			 idx;
2480
2481	if (*p == '\0') {
2482		window_pane_reset_palette(wp);
2483		return;
2484	}
2485
2486	copy = s = xstrdup(p);
2487	while (*s != '\0') {
2488		idx = strtol(s, &s, 10);
2489		if (*s != '\0' && *s != ';')
2490			goto bad;
2491		if (idx < 0 || idx >= 0x100)
2492			goto bad;
2493
2494		window_pane_unset_palette(wp, idx);
2495		if (*s == ';')
2496			s++;
2497	}
2498	free(copy);
2499	return;
2500
2501bad:
2502	log_debug("bad OSC 104: %s", p);
2503	free(copy);
2504}
2505