xref: /openbsd-src/usr.bin/tmux/input.c (revision d5f1c1a5f742ad4da45c3c3d8beb61d8583a1f17)
1*d5f1c1a5Snicm /* $OpenBSD: input.c,v 1.232 2024/11/11 08:41:05 nicm Exp $ */
2311827fbSnicm 
3311827fbSnicm /*
498ca8272Snicm  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5311827fbSnicm  *
6311827fbSnicm  * Permission to use, copy, modify, and distribute this software for any
7311827fbSnicm  * purpose with or without fee is hereby granted, provided that the above
8311827fbSnicm  * copyright notice and this permission notice appear in all copies.
9311827fbSnicm  *
10311827fbSnicm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11311827fbSnicm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12311827fbSnicm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13311827fbSnicm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14311827fbSnicm  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15311827fbSnicm  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16311827fbSnicm  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17311827fbSnicm  */
18311827fbSnicm 
19311827fbSnicm #include <sys/types.h>
20311827fbSnicm 
21f7e94a12Snicm #include <netinet/in.h>
22f7e94a12Snicm 
236e8cc4bcSnicm #include <ctype.h>
24f7e94a12Snicm #include <resolv.h>
25311827fbSnicm #include <stdlib.h>
26311827fbSnicm #include <string.h>
273ed30b78Snicm #include <time.h>
28311827fbSnicm 
29311827fbSnicm #include "tmux.h"
30311827fbSnicm 
31dee808c1Snicm /*
32dee808c1Snicm  * Based on the description by Paul Williams at:
33dee808c1Snicm  *
348f448421Snicm  * https://vt100.net/emu/dec_ansi_parser
35dee808c1Snicm  *
36dee808c1Snicm  * With the following changes:
37dee808c1Snicm  *
38dee808c1Snicm  * - 7-bit only.
39dee808c1Snicm  *
40dee808c1Snicm  * - Support for UTF-8.
41dee808c1Snicm  *
42dee808c1Snicm  * - OSC (but not APC) may be terminated by \007 as well as ST.
43dee808c1Snicm  *
44dee808c1Snicm  * - A state for APC similar to OSC. Some terminals appear to use this to set
45dee808c1Snicm  *   the title.
46dee808c1Snicm  *
47dee808c1Snicm  * - A state for the screen \033k...\033\\ sequence to rename a window. This is
48dee808c1Snicm  *   pretty stupid but not supporting it is more trouble than it is worth.
49885f7078Snicm  *
50885f7078Snicm  * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
51acf53bf7Snicm  *   be passed to the underlying terminals.
52dee808c1Snicm  */
53311827fbSnicm 
546c01012eSnicm /* Input parser cell. */
556c01012eSnicm struct input_cell {
566c01012eSnicm 	struct grid_cell	cell;
576c01012eSnicm 	int			set;
586c01012eSnicm 	int			g0set;	/* 1 if ACS */
596c01012eSnicm 	int			g1set;	/* 1 if ACS */
606c01012eSnicm };
616c01012eSnicm 
62902fbd84Snicm /* Input parser argument. */
63902fbd84Snicm struct input_param {
64902fbd84Snicm 	enum {
65902fbd84Snicm 		INPUT_MISSING,
66902fbd84Snicm 		INPUT_NUMBER,
67902fbd84Snicm 		INPUT_STRING
68902fbd84Snicm 	}			type;
69902fbd84Snicm 	union {
70902fbd84Snicm 		int		num;
71902fbd84Snicm 		char	       *str;
72902fbd84Snicm 	};
73902fbd84Snicm };
74902fbd84Snicm 
756c01012eSnicm /* Input parser context. */
766c01012eSnicm struct input_ctx {
776c01012eSnicm 	struct window_pane     *wp;
78cf6b0e8fSnicm 	struct bufferevent     *event;
796c01012eSnicm 	struct screen_write_ctx ctx;
8033a1e283Snicm 	struct colour_palette  *palette;
816c01012eSnicm 
826c01012eSnicm 	struct input_cell	cell;
836c01012eSnicm 
846c01012eSnicm 	struct input_cell	old_cell;
856c01012eSnicm 	u_int			old_cx;
866c01012eSnicm 	u_int			old_cy;
875c6c7001Snicm 	int			old_mode;
886c01012eSnicm 
896c01012eSnicm 	u_char			interm_buf[4];
906c01012eSnicm 	size_t			interm_len;
916c01012eSnicm 
926c01012eSnicm 	u_char			param_buf[64];
936c01012eSnicm 	size_t			param_len;
946c01012eSnicm 
956c01012eSnicm #define INPUT_BUF_START 32
966c01012eSnicm 	u_char		       *input_buf;
976c01012eSnicm 	size_t			input_len;
986c01012eSnicm 	size_t			input_space;
9990866723Snicm 	enum {
10090866723Snicm 		INPUT_END_ST,
10190866723Snicm 		INPUT_END_BEL
10290866723Snicm 	}			input_end;
1036c01012eSnicm 
104902fbd84Snicm 	struct input_param	param_list[24];
1056c01012eSnicm 	u_int			param_list_len;
1066c01012eSnicm 
1076c01012eSnicm 	struct utf8_data	utf8data;
108e51b0e35Snicm 	int			utf8started;
1096c01012eSnicm 
1106c01012eSnicm 	int			ch;
11180c8bfd3Snicm 	struct utf8_data	last;
1120bb7045cSnicm 
1136c01012eSnicm 	int			flags;
1146c01012eSnicm #define INPUT_DISCARD 0x1
11580c8bfd3Snicm #define INPUT_LAST 0x2
1166c01012eSnicm 
1176c01012eSnicm 	const struct input_state *state;
1186c01012eSnicm 
1195842cea5Snicm 	struct event		timer;
1205842cea5Snicm 
1216c01012eSnicm 	/*
1226c01012eSnicm 	 * All input received since we were last in the ground state. Sent to
1236c01012eSnicm 	 * control clients on connection.
1246c01012eSnicm 	 */
1256c01012eSnicm 	struct evbuffer		*since_ground;
1266c01012eSnicm };
1276c01012eSnicm 
128dee808c1Snicm /* Helper functions. */
129996c9ad8Snicm struct input_transition;
130413e5e52Snicm static int	input_split(struct input_ctx *);
131413e5e52Snicm static int	input_get(struct input_ctx *, u_int, int, int);
132413e5e52Snicm static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...);
13329ebed37Snicm static void	input_set_state(struct input_ctx *,
134413e5e52Snicm 		    const struct input_transition *);
135413e5e52Snicm static void	input_reset_cell(struct input_ctx *);
136311827fbSnicm 
13790866723Snicm static void	input_osc_4(struct input_ctx *, const char *);
1382df6775cSnicm static void	input_osc_8(struct input_ctx *, const char *);
13990866723Snicm static void	input_osc_10(struct input_ctx *, const char *);
14090866723Snicm static void	input_osc_11(struct input_ctx *, const char *);
1411db1a6bbSnicm static void	input_osc_12(struct input_ctx *, const char *);
14290866723Snicm static void	input_osc_52(struct input_ctx *, const char *);
14390866723Snicm static void	input_osc_104(struct input_ctx *, const char *);
144e68ccaeaSnicm static void	input_osc_110(struct input_ctx *, const char *);
145e68ccaeaSnicm static void	input_osc_111(struct input_ctx *, const char *);
1461db1a6bbSnicm static void	input_osc_112(struct input_ctx *, const char *);
147cbbd91a4Snicm static void	input_osc_133(struct input_ctx *, const char *);
148e16c1698Snicm 
149dee808c1Snicm /* Transition entry/exit handlers. */
150413e5e52Snicm static void	input_clear(struct input_ctx *);
151413e5e52Snicm static void	input_ground(struct input_ctx *);
1525842cea5Snicm static void	input_enter_dcs(struct input_ctx *);
153413e5e52Snicm static void	input_enter_osc(struct input_ctx *);
154413e5e52Snicm static void	input_exit_osc(struct input_ctx *);
155413e5e52Snicm static void	input_enter_apc(struct input_ctx *);
156413e5e52Snicm static void	input_exit_apc(struct input_ctx *);
157413e5e52Snicm static void	input_enter_rename(struct input_ctx *);
158413e5e52Snicm static void	input_exit_rename(struct input_ctx *);
159311827fbSnicm 
160dee808c1Snicm /* Input state handlers. */
161413e5e52Snicm static int	input_print(struct input_ctx *);
162413e5e52Snicm static int	input_intermediate(struct input_ctx *);
163413e5e52Snicm static int	input_parameter(struct input_ctx *);
164413e5e52Snicm static int	input_input(struct input_ctx *);
165413e5e52Snicm static int	input_c0_dispatch(struct input_ctx *);
166413e5e52Snicm static int	input_esc_dispatch(struct input_ctx *);
167413e5e52Snicm static int	input_csi_dispatch(struct input_ctx *);
168413e5e52Snicm static void	input_csi_dispatch_rm(struct input_ctx *);
169413e5e52Snicm static void	input_csi_dispatch_rm_private(struct input_ctx *);
170413e5e52Snicm static void	input_csi_dispatch_sm(struct input_ctx *);
171413e5e52Snicm static void	input_csi_dispatch_sm_private(struct input_ctx *);
1727b23d14cSnicm static void	input_csi_dispatch_sm_graphics(struct input_ctx *);
173413e5e52Snicm static void	input_csi_dispatch_winops(struct input_ctx *);
174413e5e52Snicm static void	input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *);
175413e5e52Snicm static void	input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *);
176413e5e52Snicm static void	input_csi_dispatch_sgr(struct input_ctx *);
177413e5e52Snicm static int	input_dcs_dispatch(struct input_ctx *);
178e51b0e35Snicm static int	input_top_bit_set(struct input_ctx *);
17990866723Snicm static int	input_end_bel(struct input_ctx *);
180311827fbSnicm 
181dee808c1Snicm /* Command table comparison function. */
182413e5e52Snicm static int	input_table_compare(const void *, const void *);
183311827fbSnicm 
184dee808c1Snicm /* Command table entry. */
185dee808c1Snicm struct input_table_entry {
186dee808c1Snicm 	int		ch;
187dee808c1Snicm 	const char     *interm;
188dee808c1Snicm 	int		type;
189311827fbSnicm };
190311827fbSnicm 
191dee808c1Snicm /* Escape commands. */
192dee808c1Snicm enum input_esc_type {
193dee808c1Snicm 	INPUT_ESC_DECALN,
194dee808c1Snicm 	INPUT_ESC_DECKPAM,
195dee808c1Snicm 	INPUT_ESC_DECKPNM,
196dee808c1Snicm 	INPUT_ESC_DECRC,
197dee808c1Snicm 	INPUT_ESC_DECSC,
198dee808c1Snicm 	INPUT_ESC_HTS,
199dee808c1Snicm 	INPUT_ESC_IND,
200dee808c1Snicm 	INPUT_ESC_NEL,
201dee808c1Snicm 	INPUT_ESC_RI,
202dee808c1Snicm 	INPUT_ESC_RIS,
203c2a06f72Snicm 	INPUT_ESC_SCSG0_OFF,
204c2a06f72Snicm 	INPUT_ESC_SCSG0_ON,
205c2a06f72Snicm 	INPUT_ESC_SCSG1_OFF,
206c2a06f72Snicm 	INPUT_ESC_SCSG1_ON,
2077b23d14cSnicm 	INPUT_ESC_ST
208dee808c1Snicm };
209dee808c1Snicm 
210dee808c1Snicm /* Escape command table. */
211413e5e52Snicm static const struct input_table_entry input_esc_table[] = {
212c2a06f72Snicm 	{ '0', "(", INPUT_ESC_SCSG0_ON },
213c2a06f72Snicm 	{ '0', ")", INPUT_ESC_SCSG1_ON },
214dee808c1Snicm 	{ '7', "",  INPUT_ESC_DECSC },
215dee808c1Snicm 	{ '8', "",  INPUT_ESC_DECRC },
216dee808c1Snicm 	{ '8', "#", INPUT_ESC_DECALN },
217dee808c1Snicm 	{ '=', "",  INPUT_ESC_DECKPAM },
218dee808c1Snicm 	{ '>', "",  INPUT_ESC_DECKPNM },
219c2a06f72Snicm 	{ 'B', "(", INPUT_ESC_SCSG0_OFF },
220c2a06f72Snicm 	{ 'B', ")", INPUT_ESC_SCSG1_OFF },
221dee808c1Snicm 	{ 'D', "",  INPUT_ESC_IND },
222dee808c1Snicm 	{ 'E', "",  INPUT_ESC_NEL },
223dee808c1Snicm 	{ 'H', "",  INPUT_ESC_HTS },
224dee808c1Snicm 	{ 'M', "",  INPUT_ESC_RI },
225e16c1698Snicm 	{ '\\', "", INPUT_ESC_ST },
226dee808c1Snicm 	{ 'c', "",  INPUT_ESC_RIS },
227dee808c1Snicm };
228dee808c1Snicm 
229dee808c1Snicm /* Control (CSI) commands. */
230dee808c1Snicm enum input_csi_type {
231dee808c1Snicm 	INPUT_CSI_CBT,
23203fa59bdSnicm 	INPUT_CSI_CNL,
23303fa59bdSnicm 	INPUT_CSI_CPL,
234dee808c1Snicm 	INPUT_CSI_CUB,
235dee808c1Snicm 	INPUT_CSI_CUD,
236dee808c1Snicm 	INPUT_CSI_CUF,
237dee808c1Snicm 	INPUT_CSI_CUP,
238dee808c1Snicm 	INPUT_CSI_CUU,
239dee808c1Snicm 	INPUT_CSI_DA,
240b9cdec04Snicm 	INPUT_CSI_DA_TWO,
241dee808c1Snicm 	INPUT_CSI_DCH,
242e5464ab3Snicm 	INPUT_CSI_DECSCUSR,
243dee808c1Snicm 	INPUT_CSI_DECSTBM,
244dee808c1Snicm 	INPUT_CSI_DL,
245dee808c1Snicm 	INPUT_CSI_DSR,
246f752bf02Snicm 	INPUT_CSI_ECH,
247dee808c1Snicm 	INPUT_CSI_ED,
248dee808c1Snicm 	INPUT_CSI_EL,
249dee808c1Snicm 	INPUT_CSI_HPA,
250dee808c1Snicm 	INPUT_CSI_ICH,
251dee808c1Snicm 	INPUT_CSI_IL,
252dcf80b09Snicm 	INPUT_CSI_MODOFF,
253dcf80b09Snicm 	INPUT_CSI_MODSET,
254dbbae13bSnicm 	INPUT_CSI_RCP,
25589444e08Snicm 	INPUT_CSI_REP,
256dee808c1Snicm 	INPUT_CSI_RM,
257dee808c1Snicm 	INPUT_CSI_RM_PRIVATE,
258dbbae13bSnicm 	INPUT_CSI_SCP,
259fa32c33cSnicm 	INPUT_CSI_SD,
260dee808c1Snicm 	INPUT_CSI_SGR,
261dee808c1Snicm 	INPUT_CSI_SM,
262dee808c1Snicm 	INPUT_CSI_SM_PRIVATE,
2637b23d14cSnicm 	INPUT_CSI_SM_GRAPHICS,
264f0063641Snicm 	INPUT_CSI_SU,
265dee808c1Snicm 	INPUT_CSI_TBC,
266dee808c1Snicm 	INPUT_CSI_VPA,
267c8af5297Snicm 	INPUT_CSI_WINOPS,
2687b23d14cSnicm 	INPUT_CSI_XDA
269dee808c1Snicm };
270dee808c1Snicm 
271dee808c1Snicm /* Control (CSI) command table. */
272413e5e52Snicm static const struct input_table_entry input_csi_table[] = {
273dee808c1Snicm 	{ '@', "",  INPUT_CSI_ICH },
274dee808c1Snicm 	{ 'A', "",  INPUT_CSI_CUU },
275dee808c1Snicm 	{ 'B', "",  INPUT_CSI_CUD },
276dee808c1Snicm 	{ 'C', "",  INPUT_CSI_CUF },
277dee808c1Snicm 	{ 'D', "",  INPUT_CSI_CUB },
27803fa59bdSnicm 	{ 'E', "",  INPUT_CSI_CNL },
27903fa59bdSnicm 	{ 'F', "",  INPUT_CSI_CPL },
280dee808c1Snicm 	{ 'G', "",  INPUT_CSI_HPA },
281dee808c1Snicm 	{ 'H', "",  INPUT_CSI_CUP },
282dee808c1Snicm 	{ 'J', "",  INPUT_CSI_ED },
283dee808c1Snicm 	{ 'K', "",  INPUT_CSI_EL },
284dee808c1Snicm 	{ 'L', "",  INPUT_CSI_IL },
285dee808c1Snicm 	{ 'M', "",  INPUT_CSI_DL },
286dee808c1Snicm 	{ 'P', "",  INPUT_CSI_DCH },
287f0063641Snicm 	{ 'S', "",  INPUT_CSI_SU },
2887b23d14cSnicm 	{ 'S', "?", INPUT_CSI_SM_GRAPHICS },
289fa32c33cSnicm 	{ 'T', "",  INPUT_CSI_SD },
290f752bf02Snicm 	{ 'X', "",  INPUT_CSI_ECH },
291dee808c1Snicm 	{ 'Z', "",  INPUT_CSI_CBT },
292edcf3982Snicm 	{ '`', "",  INPUT_CSI_HPA },
29389444e08Snicm 	{ 'b', "",  INPUT_CSI_REP },
294dee808c1Snicm 	{ 'c', "",  INPUT_CSI_DA },
295b9cdec04Snicm 	{ 'c', ">", INPUT_CSI_DA_TWO },
296dee808c1Snicm 	{ 'd', "",  INPUT_CSI_VPA },
297dee808c1Snicm 	{ 'f', "",  INPUT_CSI_CUP },
298dee808c1Snicm 	{ 'g', "",  INPUT_CSI_TBC },
299dee808c1Snicm 	{ 'h', "",  INPUT_CSI_SM },
300dee808c1Snicm 	{ 'h', "?", INPUT_CSI_SM_PRIVATE },
301dee808c1Snicm 	{ 'l', "",  INPUT_CSI_RM },
302dee808c1Snicm 	{ 'l', "?", INPUT_CSI_RM_PRIVATE },
303dee808c1Snicm 	{ 'm', "",  INPUT_CSI_SGR },
304dcf80b09Snicm 	{ 'm', ">", INPUT_CSI_MODSET },
305dee808c1Snicm 	{ 'n', "",  INPUT_CSI_DSR },
306dcf80b09Snicm 	{ 'n', ">", INPUT_CSI_MODOFF },
307e5464ab3Snicm 	{ 'q', " ", INPUT_CSI_DECSCUSR },
308ecd9db25Snicm 	{ 'q', ">", INPUT_CSI_XDA },
309dee808c1Snicm 	{ 'r', "",  INPUT_CSI_DECSTBM },
310dbbae13bSnicm 	{ 's', "",  INPUT_CSI_SCP },
311c8af5297Snicm 	{ 't', "",  INPUT_CSI_WINOPS },
3127b23d14cSnicm 	{ 'u', "",  INPUT_CSI_RCP }
313dee808c1Snicm };
314dee808c1Snicm 
315dee808c1Snicm /* Input transition. */
316dee808c1Snicm struct input_transition {
317dee808c1Snicm 	int				first;
318dee808c1Snicm 	int				last;
319dee808c1Snicm 
320dee808c1Snicm 	int				(*handler)(struct input_ctx *);
321dee808c1Snicm 	const struct input_state       *state;
322dee808c1Snicm };
323dee808c1Snicm 
324dee808c1Snicm /* Input state. */
325dee808c1Snicm struct input_state {
326dee808c1Snicm 	const char			*name;
327dee808c1Snicm 	void				(*enter)(struct input_ctx *);
328dee808c1Snicm 	void				(*exit)(struct input_ctx *);
329dee808c1Snicm 	const struct input_transition	*transitions;
330dee808c1Snicm };
331dee808c1Snicm 
332dee808c1Snicm /* State transitions available from all states. */
333dee808c1Snicm #define INPUT_STATE_ANYWHERE \
334dee808c1Snicm 	{ 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
335dee808c1Snicm 	{ 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
336dee808c1Snicm 	{ 0x1b, 0x1b, NULL,		 &input_state_esc_enter }
337dee808c1Snicm 
338dee808c1Snicm /* Forward declarations of state tables. */
339413e5e52Snicm static const struct input_transition input_state_ground_table[];
340413e5e52Snicm static const struct input_transition input_state_esc_enter_table[];
341413e5e52Snicm static const struct input_transition input_state_esc_intermediate_table[];
342413e5e52Snicm static const struct input_transition input_state_csi_enter_table[];
343413e5e52Snicm static const struct input_transition input_state_csi_parameter_table[];
344413e5e52Snicm static const struct input_transition input_state_csi_intermediate_table[];
345413e5e52Snicm static const struct input_transition input_state_csi_ignore_table[];
346413e5e52Snicm static const struct input_transition input_state_dcs_enter_table[];
347413e5e52Snicm static const struct input_transition input_state_dcs_parameter_table[];
348413e5e52Snicm static const struct input_transition input_state_dcs_intermediate_table[];
349413e5e52Snicm static const struct input_transition input_state_dcs_handler_table[];
350413e5e52Snicm static const struct input_transition input_state_dcs_escape_table[];
351413e5e52Snicm static const struct input_transition input_state_dcs_ignore_table[];
352413e5e52Snicm static const struct input_transition input_state_osc_string_table[];
353413e5e52Snicm static const struct input_transition input_state_apc_string_table[];
354413e5e52Snicm static const struct input_transition input_state_rename_string_table[];
355413e5e52Snicm static const struct input_transition input_state_consume_st_table[];
356dee808c1Snicm 
357dee808c1Snicm /* ground state definition. */
358413e5e52Snicm static const struct input_state input_state_ground = {
359dee808c1Snicm 	"ground",
3602b3ef6e2Snicm 	input_ground, NULL,
361dee808c1Snicm 	input_state_ground_table
362dee808c1Snicm };
363dee808c1Snicm 
364dee808c1Snicm /* esc_enter state definition. */
365413e5e52Snicm static const struct input_state input_state_esc_enter = {
366dee808c1Snicm 	"esc_enter",
367dee808c1Snicm 	input_clear, NULL,
368dee808c1Snicm 	input_state_esc_enter_table
369dee808c1Snicm };
370dee808c1Snicm 
371dee808c1Snicm /* esc_intermediate state definition. */
372413e5e52Snicm static const struct input_state input_state_esc_intermediate = {
373dee808c1Snicm 	"esc_intermediate",
374dee808c1Snicm 	NULL, NULL,
375dee808c1Snicm 	input_state_esc_intermediate_table
376dee808c1Snicm };
377dee808c1Snicm 
378dee808c1Snicm /* csi_enter state definition. */
379413e5e52Snicm static const struct input_state input_state_csi_enter = {
380dee808c1Snicm 	"csi_enter",
381dee808c1Snicm 	input_clear, NULL,
382dee808c1Snicm 	input_state_csi_enter_table
383dee808c1Snicm };
384dee808c1Snicm 
385dee808c1Snicm /* csi_parameter state definition. */
386413e5e52Snicm static const struct input_state input_state_csi_parameter = {
387dee808c1Snicm 	"csi_parameter",
388dee808c1Snicm 	NULL, NULL,
389dee808c1Snicm 	input_state_csi_parameter_table
390dee808c1Snicm };
391dee808c1Snicm 
392dee808c1Snicm /* csi_intermediate state definition. */
393413e5e52Snicm static const struct input_state input_state_csi_intermediate = {
394dee808c1Snicm 	"csi_intermediate",
395dee808c1Snicm 	NULL, NULL,
396dee808c1Snicm 	input_state_csi_intermediate_table
397dee808c1Snicm };
398dee808c1Snicm 
399dee808c1Snicm /* csi_ignore state definition. */
400413e5e52Snicm static const struct input_state input_state_csi_ignore = {
401dee808c1Snicm 	"csi_ignore",
402dee808c1Snicm 	NULL, NULL,
403dee808c1Snicm 	input_state_csi_ignore_table
404dee808c1Snicm };
405dee808c1Snicm 
406dee808c1Snicm /* dcs_enter state definition. */
407413e5e52Snicm static const struct input_state input_state_dcs_enter = {
408dee808c1Snicm 	"dcs_enter",
4095842cea5Snicm 	input_enter_dcs, NULL,
410dee808c1Snicm 	input_state_dcs_enter_table
411dee808c1Snicm };
412dee808c1Snicm 
413dee808c1Snicm /* dcs_parameter state definition. */
414413e5e52Snicm static const struct input_state input_state_dcs_parameter = {
415dee808c1Snicm 	"dcs_parameter",
416dee808c1Snicm 	NULL, NULL,
417dee808c1Snicm 	input_state_dcs_parameter_table
418dee808c1Snicm };
419dee808c1Snicm 
420dee808c1Snicm /* dcs_intermediate state definition. */
421413e5e52Snicm static const struct input_state input_state_dcs_intermediate = {
422dee808c1Snicm 	"dcs_intermediate",
423dee808c1Snicm 	NULL, NULL,
424dee808c1Snicm 	input_state_dcs_intermediate_table
425dee808c1Snicm };
426dee808c1Snicm 
427dee808c1Snicm /* dcs_handler state definition. */
428413e5e52Snicm static const struct input_state input_state_dcs_handler = {
429dee808c1Snicm 	"dcs_handler",
430885f7078Snicm 	NULL, NULL,
431dee808c1Snicm 	input_state_dcs_handler_table
432dee808c1Snicm };
433dee808c1Snicm 
434885f7078Snicm /* dcs_escape state definition. */
435413e5e52Snicm static const struct input_state input_state_dcs_escape = {
436885f7078Snicm 	"dcs_escape",
437885f7078Snicm 	NULL, NULL,
438885f7078Snicm 	input_state_dcs_escape_table
439885f7078Snicm };
440885f7078Snicm 
441dee808c1Snicm /* dcs_ignore state definition. */
442413e5e52Snicm static const struct input_state input_state_dcs_ignore = {
443dee808c1Snicm 	"dcs_ignore",
444dee808c1Snicm 	NULL, NULL,
445dee808c1Snicm 	input_state_dcs_ignore_table
446dee808c1Snicm };
447dee808c1Snicm 
448dee808c1Snicm /* osc_string state definition. */
449413e5e52Snicm static const struct input_state input_state_osc_string = {
450dee808c1Snicm 	"osc_string",
451dee808c1Snicm 	input_enter_osc, input_exit_osc,
452dee808c1Snicm 	input_state_osc_string_table
453dee808c1Snicm };
454dee808c1Snicm 
455dee808c1Snicm /* apc_string state definition. */
456413e5e52Snicm static const struct input_state input_state_apc_string = {
457dee808c1Snicm 	"apc_string",
458dee808c1Snicm 	input_enter_apc, input_exit_apc,
459dee808c1Snicm 	input_state_apc_string_table
460dee808c1Snicm };
461dee808c1Snicm 
462dee808c1Snicm /* rename_string state definition. */
463413e5e52Snicm static const struct input_state input_state_rename_string = {
464dee808c1Snicm 	"rename_string",
465dee808c1Snicm 	input_enter_rename, input_exit_rename,
466dee808c1Snicm 	input_state_rename_string_table
467dee808c1Snicm };
468dee808c1Snicm 
469dee808c1Snicm /* consume_st state definition. */
470413e5e52Snicm static const struct input_state input_state_consume_st = {
471dee808c1Snicm 	"consume_st",
472c476faa3Snicm 	input_enter_rename, NULL, /* rename also waits for ST */
473dee808c1Snicm 	input_state_consume_st_table
474dee808c1Snicm };
475dee808c1Snicm 
476dee808c1Snicm /* ground state table. */
477413e5e52Snicm static const struct input_transition input_state_ground_table[] = {
478dee808c1Snicm 	INPUT_STATE_ANYWHERE,
479dee808c1Snicm 
480dee808c1Snicm 	{ 0x00, 0x17, input_c0_dispatch, NULL },
481dee808c1Snicm 	{ 0x19, 0x19, input_c0_dispatch, NULL },
482dee808c1Snicm 	{ 0x1c, 0x1f, input_c0_dispatch, NULL },
483dee808c1Snicm 	{ 0x20, 0x7e, input_print,	 NULL },
484dee808c1Snicm 	{ 0x7f, 0x7f, NULL,		 NULL },
485e51b0e35Snicm 	{ 0x80, 0xff, input_top_bit_set, NULL },
486dee808c1Snicm 
487dee808c1Snicm 	{ -1, -1, NULL, NULL }
488dee808c1Snicm };
489dee808c1Snicm 
490dee808c1Snicm /* esc_enter state table. */
491413e5e52Snicm static const struct input_transition input_state_esc_enter_table[] = {
492dee808c1Snicm 	INPUT_STATE_ANYWHERE,
493dee808c1Snicm 
494dee808c1Snicm 	{ 0x00, 0x17, input_c0_dispatch,  NULL },
495dee808c1Snicm 	{ 0x19, 0x19, input_c0_dispatch,  NULL },
496dee808c1Snicm 	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
497dee808c1Snicm 	{ 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
498dee808c1Snicm 	{ 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
499dee808c1Snicm 	{ 0x50, 0x50, NULL,		  &input_state_dcs_enter },
500dee808c1Snicm 	{ 0x51, 0x57, input_esc_dispatch, &input_state_ground },
501dee808c1Snicm 	{ 0x58, 0x58, NULL,		  &input_state_consume_st },
502dee808c1Snicm 	{ 0x59, 0x59, input_esc_dispatch, &input_state_ground },
503dee808c1Snicm 	{ 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
504dee808c1Snicm 	{ 0x5b, 0x5b, NULL,		  &input_state_csi_enter },
505dee808c1Snicm 	{ 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
506dee808c1Snicm 	{ 0x5d, 0x5d, NULL,		  &input_state_osc_string },
507dee808c1Snicm 	{ 0x5e, 0x5e, NULL,		  &input_state_consume_st },
508dee808c1Snicm 	{ 0x5f, 0x5f, NULL,		  &input_state_apc_string },
509dee808c1Snicm 	{ 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
510dee808c1Snicm 	{ 0x6b, 0x6b, NULL,		  &input_state_rename_string },
51118deb980Snicm 	{ 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
512dee808c1Snicm 	{ 0x7f, 0xff, NULL,		  NULL },
513dee808c1Snicm 
514dee808c1Snicm 	{ -1, -1, NULL, NULL }
515dee808c1Snicm };
516dee808c1Snicm 
51790866723Snicm /* esc_intermediate state table. */
518413e5e52Snicm static const struct input_transition input_state_esc_intermediate_table[] = {
519dee808c1Snicm 	INPUT_STATE_ANYWHERE,
520dee808c1Snicm 
521dee808c1Snicm 	{ 0x00, 0x17, input_c0_dispatch,  NULL },
522dee808c1Snicm 	{ 0x19, 0x19, input_c0_dispatch,  NULL },
523dee808c1Snicm 	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
524dee808c1Snicm 	{ 0x20, 0x2f, input_intermediate, NULL },
525dee808c1Snicm 	{ 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
526dee808c1Snicm 	{ 0x7f, 0xff, NULL,		  NULL },
527dee808c1Snicm 
528dee808c1Snicm 	{ -1, -1, NULL, NULL }
529dee808c1Snicm };
530dee808c1Snicm 
531dee808c1Snicm /* csi_enter state table. */
532413e5e52Snicm static const struct input_transition input_state_csi_enter_table[] = {
533dee808c1Snicm 	INPUT_STATE_ANYWHERE,
534dee808c1Snicm 
535dee808c1Snicm 	{ 0x00, 0x17, input_c0_dispatch,  NULL },
536dee808c1Snicm 	{ 0x19, 0x19, input_c0_dispatch,  NULL },
537dee808c1Snicm 	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
538dee808c1Snicm 	{ 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
539dee808c1Snicm 	{ 0x30, 0x39, input_parameter,	  &input_state_csi_parameter },
540902fbd84Snicm 	{ 0x3a, 0x3a, input_parameter,	  &input_state_csi_parameter },
541dee808c1Snicm 	{ 0x3b, 0x3b, input_parameter,	  &input_state_csi_parameter },
542dee808c1Snicm 	{ 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
543dee808c1Snicm 	{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
544dee808c1Snicm 	{ 0x7f, 0xff, NULL,		  NULL },
545dee808c1Snicm 
546dee808c1Snicm 	{ -1, -1, NULL, NULL }
547dee808c1Snicm };
548dee808c1Snicm 
549dee808c1Snicm /* csi_parameter state table. */
550413e5e52Snicm static const struct input_transition input_state_csi_parameter_table[] = {
551dee808c1Snicm 	INPUT_STATE_ANYWHERE,
552dee808c1Snicm 
553dee808c1Snicm 	{ 0x00, 0x17, input_c0_dispatch,  NULL },
554dee808c1Snicm 	{ 0x19, 0x19, input_c0_dispatch,  NULL },
555dee808c1Snicm 	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
556dee808c1Snicm 	{ 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
557dee808c1Snicm 	{ 0x30, 0x39, input_parameter,	  NULL },
558902fbd84Snicm 	{ 0x3a, 0x3a, input_parameter,	  NULL },
559dee808c1Snicm 	{ 0x3b, 0x3b, input_parameter,	  NULL },
560dee808c1Snicm 	{ 0x3c, 0x3f, NULL,		  &input_state_csi_ignore },
561dee808c1Snicm 	{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
562dee808c1Snicm 	{ 0x7f, 0xff, NULL,		  NULL },
563dee808c1Snicm 
564dee808c1Snicm 	{ -1, -1, NULL, NULL }
565dee808c1Snicm };
566dee808c1Snicm 
567dee808c1Snicm /* csi_intermediate state table. */
568413e5e52Snicm static const struct input_transition input_state_csi_intermediate_table[] = {
569dee808c1Snicm 	INPUT_STATE_ANYWHERE,
570dee808c1Snicm 
571dee808c1Snicm 	{ 0x00, 0x17, input_c0_dispatch,  NULL },
572dee808c1Snicm 	{ 0x19, 0x19, input_c0_dispatch,  NULL },
573dee808c1Snicm 	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
574dee808c1Snicm 	{ 0x20, 0x2f, input_intermediate, NULL },
575dee808c1Snicm 	{ 0x30, 0x3f, NULL,		  &input_state_csi_ignore },
576dee808c1Snicm 	{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
577dee808c1Snicm 	{ 0x7f, 0xff, NULL,		  NULL },
578dee808c1Snicm 
579dee808c1Snicm 	{ -1, -1, NULL, NULL }
580dee808c1Snicm };
581dee808c1Snicm 
582dee808c1Snicm /* csi_ignore state table. */
583413e5e52Snicm static const struct input_transition input_state_csi_ignore_table[] = {
584dee808c1Snicm 	INPUT_STATE_ANYWHERE,
585dee808c1Snicm 
586dee808c1Snicm 	{ 0x00, 0x17, input_c0_dispatch, NULL },
587dee808c1Snicm 	{ 0x19, 0x19, input_c0_dispatch, NULL },
588dee808c1Snicm 	{ 0x1c, 0x1f, input_c0_dispatch, NULL },
589dee808c1Snicm 	{ 0x20, 0x3f, NULL,		 NULL },
590dee808c1Snicm 	{ 0x40, 0x7e, NULL,		 &input_state_ground },
591dee808c1Snicm 	{ 0x7f, 0xff, NULL,		 NULL },
592dee808c1Snicm 
593dee808c1Snicm 	{ -1, -1, NULL, NULL }
594dee808c1Snicm };
595dee808c1Snicm 
596dee808c1Snicm /* dcs_enter state table. */
597413e5e52Snicm static const struct input_transition input_state_dcs_enter_table[] = {
598dee808c1Snicm 	INPUT_STATE_ANYWHERE,
599dee808c1Snicm 
600dee808c1Snicm 	{ 0x00, 0x17, NULL,		  NULL },
601dee808c1Snicm 	{ 0x19, 0x19, NULL,		  NULL },
602dee808c1Snicm 	{ 0x1c, 0x1f, NULL,		  NULL },
603dee808c1Snicm 	{ 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
604dee808c1Snicm 	{ 0x30, 0x39, input_parameter,	  &input_state_dcs_parameter },
605dee808c1Snicm 	{ 0x3a, 0x3a, NULL,		  &input_state_dcs_ignore },
606dee808c1Snicm 	{ 0x3b, 0x3b, input_parameter,	  &input_state_dcs_parameter },
607dee808c1Snicm 	{ 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
608885f7078Snicm 	{ 0x40, 0x7e, input_input,	  &input_state_dcs_handler },
609dee808c1Snicm 	{ 0x7f, 0xff, NULL,		  NULL },
610dee808c1Snicm 
611dee808c1Snicm 	{ -1, -1, NULL, NULL }
612dee808c1Snicm };
613dee808c1Snicm 
614dee808c1Snicm /* dcs_parameter state table. */
615413e5e52Snicm static const struct input_transition input_state_dcs_parameter_table[] = {
616dee808c1Snicm 	INPUT_STATE_ANYWHERE,
617dee808c1Snicm 
618dee808c1Snicm 	{ 0x00, 0x17, NULL,		  NULL },
619dee808c1Snicm 	{ 0x19, 0x19, NULL,		  NULL },
620dee808c1Snicm 	{ 0x1c, 0x1f, NULL,		  NULL },
621dee808c1Snicm 	{ 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
622dee808c1Snicm 	{ 0x30, 0x39, input_parameter,	  NULL },
623dee808c1Snicm 	{ 0x3a, 0x3a, NULL,		  &input_state_dcs_ignore },
624dee808c1Snicm 	{ 0x3b, 0x3b, input_parameter,	  NULL },
625dee808c1Snicm 	{ 0x3c, 0x3f, NULL,		  &input_state_dcs_ignore },
626885f7078Snicm 	{ 0x40, 0x7e, input_input,	  &input_state_dcs_handler },
627dee808c1Snicm 	{ 0x7f, 0xff, NULL,		  NULL },
628dee808c1Snicm 
629dee808c1Snicm 	{ -1, -1, NULL, NULL }
630dee808c1Snicm };
631dee808c1Snicm 
63290866723Snicm /* dcs_intermediate state table. */
633413e5e52Snicm static const struct input_transition input_state_dcs_intermediate_table[] = {
634dee808c1Snicm 	INPUT_STATE_ANYWHERE,
635dee808c1Snicm 
636dee808c1Snicm 	{ 0x00, 0x17, NULL,		  NULL },
637dee808c1Snicm 	{ 0x19, 0x19, NULL,		  NULL },
638dee808c1Snicm 	{ 0x1c, 0x1f, NULL,		  NULL },
639dee808c1Snicm 	{ 0x20, 0x2f, input_intermediate, NULL },
640dee808c1Snicm 	{ 0x30, 0x3f, NULL,		  &input_state_dcs_ignore },
641885f7078Snicm 	{ 0x40, 0x7e, input_input,	  &input_state_dcs_handler },
642dee808c1Snicm 	{ 0x7f, 0xff, NULL,		  NULL },
643dee808c1Snicm 
644dee808c1Snicm 	{ -1, -1, NULL, NULL }
645dee808c1Snicm };
646dee808c1Snicm 
647dee808c1Snicm /* dcs_handler state table. */
648413e5e52Snicm static const struct input_transition input_state_dcs_handler_table[] = {
649885f7078Snicm 	/* No INPUT_STATE_ANYWHERE */
650dee808c1Snicm 
651885f7078Snicm 	{ 0x00, 0x1a, input_input,  NULL },
652885f7078Snicm 	{ 0x1b, 0x1b, NULL,	    &input_state_dcs_escape },
653885f7078Snicm 	{ 0x1c, 0xff, input_input,  NULL },
654885f7078Snicm 
655885f7078Snicm 	{ -1, -1, NULL, NULL }
656885f7078Snicm };
657885f7078Snicm 
658885f7078Snicm /* dcs_escape state table. */
659413e5e52Snicm static const struct input_transition input_state_dcs_escape_table[] = {
660885f7078Snicm 	/* No INPUT_STATE_ANYWHERE */
661885f7078Snicm 
662885f7078Snicm 	{ 0x00, 0x5b, input_input,	  &input_state_dcs_handler },
663885f7078Snicm 	{ 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
664885f7078Snicm 	{ 0x5d, 0xff, input_input,	  &input_state_dcs_handler },
665dee808c1Snicm 
666dee808c1Snicm 	{ -1, -1, NULL, NULL }
667dee808c1Snicm };
668dee808c1Snicm 
6695ea6a24aSnicm /* dcs_ignore state table. */
670413e5e52Snicm static const struct input_transition input_state_dcs_ignore_table[] = {
671dee808c1Snicm 	INPUT_STATE_ANYWHERE,
672dee808c1Snicm 
673dee808c1Snicm 	{ 0x00, 0x17, NULL,	    NULL },
674dee808c1Snicm 	{ 0x19, 0x19, NULL,	    NULL },
675dee808c1Snicm 	{ 0x1c, 0x1f, NULL,	    NULL },
676dee808c1Snicm 	{ 0x20, 0xff, NULL,	    NULL },
677dee808c1Snicm 
678dee808c1Snicm 	{ -1, -1, NULL, NULL }
679dee808c1Snicm };
680dee808c1Snicm 
681dee808c1Snicm /* osc_string state table. */
682413e5e52Snicm static const struct input_transition input_state_osc_string_table[] = {
683dee808c1Snicm 	INPUT_STATE_ANYWHERE,
684dee808c1Snicm 
685dee808c1Snicm 	{ 0x00, 0x06, NULL,	     NULL },
68690866723Snicm 	{ 0x07, 0x07, input_end_bel, &input_state_ground },
687dee808c1Snicm 	{ 0x08, 0x17, NULL,	     NULL },
688dee808c1Snicm 	{ 0x19, 0x19, NULL,	     NULL },
689dee808c1Snicm 	{ 0x1c, 0x1f, NULL,	     NULL },
690dee808c1Snicm 	{ 0x20, 0xff, input_input,   NULL },
691dee808c1Snicm 
692dee808c1Snicm 	{ -1, -1, NULL, NULL }
693dee808c1Snicm };
694dee808c1Snicm 
695dee808c1Snicm /* apc_string state table. */
696413e5e52Snicm static const struct input_transition input_state_apc_string_table[] = {
697dee808c1Snicm 	INPUT_STATE_ANYWHERE,
698dee808c1Snicm 
699dee808c1Snicm 	{ 0x00, 0x17, NULL,	    NULL },
700dee808c1Snicm 	{ 0x19, 0x19, NULL,	    NULL },
701dee808c1Snicm 	{ 0x1c, 0x1f, NULL,	    NULL },
702dee808c1Snicm 	{ 0x20, 0xff, input_input,  NULL },
703dee808c1Snicm 
704dee808c1Snicm 	{ -1, -1, NULL, NULL }
705dee808c1Snicm };
706dee808c1Snicm 
707dee808c1Snicm /* rename_string state table. */
708413e5e52Snicm static const struct input_transition input_state_rename_string_table[] = {
709dee808c1Snicm 	INPUT_STATE_ANYWHERE,
710dee808c1Snicm 
711dee808c1Snicm 	{ 0x00, 0x17, NULL,	    NULL },
712dee808c1Snicm 	{ 0x19, 0x19, NULL,	    NULL },
713dee808c1Snicm 	{ 0x1c, 0x1f, NULL,	    NULL },
714dee808c1Snicm 	{ 0x20, 0xff, input_input,  NULL },
715dee808c1Snicm 
716dee808c1Snicm 	{ -1, -1, NULL, NULL }
717dee808c1Snicm };
718dee808c1Snicm 
719dee808c1Snicm /* consume_st state table. */
720413e5e52Snicm static const struct input_transition input_state_consume_st_table[] = {
721dee808c1Snicm 	INPUT_STATE_ANYWHERE,
722dee808c1Snicm 
723dee808c1Snicm 	{ 0x00, 0x17, NULL,	    NULL },
724dee808c1Snicm 	{ 0x19, 0x19, NULL,	    NULL },
725dee808c1Snicm 	{ 0x1c, 0x1f, NULL,	    NULL },
726dee808c1Snicm 	{ 0x20, 0xff, NULL,	    NULL },
727dee808c1Snicm 
728dee808c1Snicm 	{ -1, -1, NULL, NULL }
729dee808c1Snicm };
730dee808c1Snicm 
731*d5f1c1a5Snicm /* Maximum of bytes allowed to read in a single input. */
732*d5f1c1a5Snicm static size_t input_buffer_size = INPUT_BUF_DEFAULT_SIZE;
733*d5f1c1a5Snicm 
734dee808c1Snicm /* Input table compare. */
735413e5e52Snicm static int
736dee808c1Snicm input_table_compare(const void *key, const void *value)
737311827fbSnicm {
738dee808c1Snicm 	const struct input_ctx		*ictx = key;
739dee808c1Snicm 	const struct input_table_entry	*entry = value;
740311827fbSnicm 
741dee808c1Snicm 	if (ictx->ch != entry->ch)
742dee808c1Snicm 		return (ictx->ch - entry->ch);
743dee808c1Snicm 	return (strcmp(ictx->interm_buf, entry->interm));
744311827fbSnicm }
745311827fbSnicm 
7465842cea5Snicm /*
7475842cea5Snicm  * Timer - if this expires then have been waiting for a terminator for too
7485842cea5Snicm  * long, so reset to ground.
7495842cea5Snicm  */
7505842cea5Snicm static void
7515842cea5Snicm input_timer_callback(__unused int fd, __unused short events, void *arg)
7525842cea5Snicm {
7535842cea5Snicm 	struct input_ctx	*ictx = arg;
7545842cea5Snicm 
75529ebed37Snicm 	log_debug("%s: %s expired" , __func__, ictx->state->name);
75629ebed37Snicm 	input_reset(ictx, 0);
7575842cea5Snicm }
7585842cea5Snicm 
7595842cea5Snicm /* Start the timer. */
7605842cea5Snicm static void
7615842cea5Snicm input_start_timer(struct input_ctx *ictx)
7625842cea5Snicm {
763d7dc1b61Snicm 	struct timeval	tv = { .tv_sec = 5, .tv_usec = 0 };
7645842cea5Snicm 
7655842cea5Snicm 	event_del(&ictx->timer);
7665842cea5Snicm 	event_add(&ictx->timer, &tv);
7675842cea5Snicm }
7685842cea5Snicm 
769c2a06f72Snicm /* Reset cell state to default. */
770413e5e52Snicm static void
771c2a06f72Snicm input_reset_cell(struct input_ctx *ictx)
772c2a06f72Snicm {
773c2a06f72Snicm 	memcpy(&ictx->cell.cell, &grid_default_cell, sizeof ictx->cell.cell);
774c2a06f72Snicm 	ictx->cell.set = 0;
775c2a06f72Snicm 	ictx->cell.g0set = ictx->cell.g1set = 0;
776c2a06f72Snicm 
777c2a06f72Snicm 	memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
778c2a06f72Snicm 	ictx->old_cx = 0;
779c2a06f72Snicm 	ictx->old_cy = 0;
780c2a06f72Snicm }
781c2a06f72Snicm 
7825c6c7001Snicm /* Save screen state. */
7835c6c7001Snicm static void
7845c6c7001Snicm input_save_state(struct input_ctx *ictx)
7855c6c7001Snicm {
7865c6c7001Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
7875c6c7001Snicm 	struct screen		*s = sctx->s;
7885c6c7001Snicm 
7895c6c7001Snicm 	memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
7905c6c7001Snicm 	ictx->old_cx = s->cx;
7915c6c7001Snicm 	ictx->old_cy = s->cy;
7925c6c7001Snicm 	ictx->old_mode = s->mode;
7935c6c7001Snicm }
7945c6c7001Snicm 
795f70f8bd4Snicm /* Restore screen state. */
7965c6c7001Snicm static void
7975c6c7001Snicm input_restore_state(struct input_ctx *ictx)
7985c6c7001Snicm {
7995c6c7001Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
8005c6c7001Snicm 
8015c6c7001Snicm 	memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
8025c6c7001Snicm 	if (ictx->old_mode & MODE_ORIGIN)
8035c6c7001Snicm 		screen_write_mode_set(sctx, MODE_ORIGIN);
8045c6c7001Snicm 	else
8055c6c7001Snicm 		screen_write_mode_clear(sctx, MODE_ORIGIN);
8065c6c7001Snicm 	screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy, 0);
8075c6c7001Snicm }
8085c6c7001Snicm 
809dee808c1Snicm /* Initialise input parser. */
81029ebed37Snicm struct input_ctx *
81133a1e283Snicm input_init(struct window_pane *wp, struct bufferevent *bev,
81233a1e283Snicm     struct colour_palette *palette)
813311827fbSnicm {
8146c01012eSnicm 	struct input_ctx	*ictx;
8156c01012eSnicm 
81629ebed37Snicm 	ictx = xcalloc(1, sizeof *ictx);
81729ebed37Snicm 	ictx->wp = wp;
818cf6b0e8fSnicm 	ictx->event = bev;
81933a1e283Snicm 	ictx->palette = palette;
820311827fbSnicm 
8212b3ef6e2Snicm 	ictx->input_space = INPUT_BUF_START;
8222b3ef6e2Snicm 	ictx->input_buf = xmalloc(INPUT_BUF_START);
8232b3ef6e2Snicm 
824996c9ad8Snicm 	ictx->since_ground = evbuffer_new();
825b32e1d34Snicm 	if (ictx->since_ground == NULL)
826b32e1d34Snicm 		fatalx("out of memory");
827b2f7d8c8Snicm 
8285842cea5Snicm 	evtimer_set(&ictx->timer, input_timer_callback, ictx);
8295842cea5Snicm 
83029ebed37Snicm 	input_reset(ictx, 0);
83129ebed37Snicm 	return (ictx);
832311827fbSnicm }
833311827fbSnicm 
834dee808c1Snicm /* Destroy input parser. */
835311827fbSnicm void
83629ebed37Snicm input_free(struct input_ctx *ictx)
837311827fbSnicm {
838902fbd84Snicm 	u_int	i;
839902fbd84Snicm 
840902fbd84Snicm 	for (i = 0; i < ictx->param_list_len; i++) {
841902fbd84Snicm 		if (ictx->param_list[i].type == INPUT_STRING)
842902fbd84Snicm 			free(ictx->param_list[i].str);
843902fbd84Snicm 	}
8442b3ef6e2Snicm 
8455842cea5Snicm 	event_del(&ictx->timer);
8465842cea5Snicm 
8476c01012eSnicm 	free(ictx->input_buf);
8486c01012eSnicm 	evbuffer_free(ictx->since_ground);
8496c01012eSnicm 
8506c01012eSnicm 	free(ictx);
8516c01012eSnicm }
8526c01012eSnicm 
8536c01012eSnicm /* Reset input state and clear screen. */
8546c01012eSnicm void
85529ebed37Snicm input_reset(struct input_ctx *ictx, int clear)
8566c01012eSnicm {
8573248c880Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
85829ebed37Snicm 	struct window_pane	*wp = ictx->wp;
8596c01012eSnicm 
860c971e5c9Snicm 	input_reset_cell(ictx);
8616c01012eSnicm 
86229ebed37Snicm 	if (clear && wp != NULL) {
8632c8678f7Snicm 		if (TAILQ_EMPTY(&wp->modes))
86483e83a91Snicm 			screen_write_start_pane(sctx, wp, &wp->base);
8656c01012eSnicm 		else
86683e83a91Snicm 			screen_write_start(sctx, &wp->base);
8673248c880Snicm 		screen_write_reset(sctx);
8683248c880Snicm 		screen_write_stop(sctx);
8696c01012eSnicm 	}
8706c01012eSnicm 
8715842cea5Snicm 	input_clear(ictx);
872b2f7d8c8Snicm 
873b2f7d8c8Snicm 	ictx->state = &input_state_ground;
874b2f7d8c8Snicm 	ictx->flags = 0;
875b2f7d8c8Snicm }
876b2f7d8c8Snicm 
8776c01012eSnicm /* Return pending data. */
8786c01012eSnicm struct evbuffer *
87929ebed37Snicm input_pending(struct input_ctx *ictx)
8806c01012eSnicm {
88129ebed37Snicm 	return (ictx->since_ground);
882996c9ad8Snicm }
883996c9ad8Snicm 
884996c9ad8Snicm /* Change input state. */
885413e5e52Snicm static void
88629ebed37Snicm input_set_state(struct input_ctx *ictx, const struct input_transition *itr)
887996c9ad8Snicm {
888996c9ad8Snicm 	if (ictx->state->exit != NULL)
889996c9ad8Snicm 		ictx->state->exit(ictx);
890996c9ad8Snicm 	ictx->state = itr->state;
891996c9ad8Snicm 	if (ictx->state->enter != NULL)
892996c9ad8Snicm 		ictx->state->enter(ictx);
893311827fbSnicm }
894311827fbSnicm 
89529ebed37Snicm /* Parse data. */
89629ebed37Snicm static void
89729ebed37Snicm input_parse(struct input_ctx *ictx, u_char *buf, size_t len)
898311827fbSnicm {
8993248c880Snicm 	struct screen_write_ctx		*sctx = &ictx->ctx;
90026a51baaSnicm 	const struct input_state	*state = NULL;
90126a51baaSnicm 	const struct input_transition	*itr = NULL;
902fb601f47Snicm 	size_t				 off = 0;
903311827fbSnicm 
904dee808c1Snicm 	/* Parse the input. */
905dee808c1Snicm 	while (off < len) {
906dee808c1Snicm 		ictx->ch = buf[off++];
907dee808c1Snicm 
908dee808c1Snicm 		/* Find the transition. */
90926a51baaSnicm 		if (ictx->state != state ||
91026a51baaSnicm 		    itr == NULL ||
91126a51baaSnicm 		    ictx->ch < itr->first ||
91226a51baaSnicm 		    ictx->ch > itr->last) {
913dee808c1Snicm 			itr = ictx->state->transitions;
914dee808c1Snicm 			while (itr->first != -1 && itr->last != -1) {
9152d71b92eSnicm 				if (ictx->ch >= itr->first &&
9162d71b92eSnicm 				    ictx->ch <= itr->last)
917dee808c1Snicm 					break;
918dee808c1Snicm 				itr++;
919311827fbSnicm 			}
920dee808c1Snicm 			if (itr->first == -1 || itr->last == -1) {
921dee808c1Snicm 				/* No transition? Eh? */
922bd33b720Snicm 				fatalx("no transition from state");
923311827fbSnicm 			}
92426a51baaSnicm 		}
92526a51baaSnicm 		state = ictx->state;
926311827fbSnicm 
9278ba522d1Snicm 		/*
9288248eab7Snicm 		 * Any state except print stops the current collection. This is
9298248eab7Snicm 		 * an optimization to avoid checking if the attributes have
9308248eab7Snicm 		 * changed for every character. It will stop unnecessarily for
9318248eab7Snicm 		 * sequences that don't make a terminal change, but they should
9328248eab7Snicm 		 * be the minority.
9338248eab7Snicm 		 */
9348248eab7Snicm 		if (itr->handler != input_print)
9353248c880Snicm 			screen_write_collect_end(sctx);
9368248eab7Snicm 
9378248eab7Snicm 		/*
938dee808c1Snicm 		 * Execute the handler, if any. Don't switch state if it
939dee808c1Snicm 		 * returns non-zero.
9408ba522d1Snicm 		 */
9416c0f147dSnicm 		if (itr->handler != NULL && itr->handler(ictx) != 0)
942dee808c1Snicm 			continue;
943dee808c1Snicm 
944dee808c1Snicm 		/* And switch state, if necessary. */
945996c9ad8Snicm 		if (itr->state != NULL)
94629ebed37Snicm 			input_set_state(ictx, itr);
947996c9ad8Snicm 
948996c9ad8Snicm 		/* If not in ground state, save input. */
949996c9ad8Snicm 		if (ictx->state != &input_state_ground)
950996c9ad8Snicm 			evbuffer_add(ictx->since_ground, &ictx->ch, 1);
951311827fbSnicm 	}
95229ebed37Snicm }
9538ba522d1Snicm 
95429ebed37Snicm /* Parse input from pane. */
95529ebed37Snicm void
95629ebed37Snicm input_parse_pane(struct window_pane *wp)
95729ebed37Snicm {
9582920028dSnicm 	void	*new_data;
9592920028dSnicm 	size_t	 new_size;
96029ebed37Snicm 
9612920028dSnicm 	new_data = window_pane_get_new_data(wp, &wp->offset, &new_size);
9622920028dSnicm 	input_parse_buffer(wp, new_data, new_size);
963a34cf9c8Snicm 	window_pane_update_used_data(wp, &wp->offset, new_size);
96429ebed37Snicm }
96529ebed37Snicm 
96629ebed37Snicm /* Parse given input. */
96729ebed37Snicm void
96829ebed37Snicm input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
96929ebed37Snicm {
97029ebed37Snicm 	struct input_ctx	*ictx = wp->ictx;
97129ebed37Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
97229ebed37Snicm 
97329ebed37Snicm 	if (len == 0)
97429ebed37Snicm 		return;
97529ebed37Snicm 
97629ebed37Snicm 	window_update_activity(wp->window);
97729ebed37Snicm 	wp->flags |= PANE_CHANGED;
97829ebed37Snicm 
979d7514f5bSnicm 	/* Flag new input while in a mode. */
980d7514f5bSnicm 	if (!TAILQ_EMPTY(&wp->modes))
981d7514f5bSnicm 		wp->flags |= PANE_UNSEENCHANGES;
982d7514f5bSnicm 
98329ebed37Snicm 	/* NULL wp if there is a mode set as don't want to update the tty. */
98429ebed37Snicm 	if (TAILQ_EMPTY(&wp->modes))
98583e83a91Snicm 		screen_write_start_pane(sctx, wp, &wp->base);
98629ebed37Snicm 	else
98783e83a91Snicm 		screen_write_start(sctx, &wp->base);
98829ebed37Snicm 
98929ebed37Snicm 	log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
99029ebed37Snicm 	    ictx->state->name, len, (int)len, buf);
99129ebed37Snicm 
99229ebed37Snicm 	input_parse(ictx, buf, len);
99329ebed37Snicm 	screen_write_stop(sctx);
99429ebed37Snicm }
99529ebed37Snicm 
99629ebed37Snicm /* Parse given input for screen. */
99729ebed37Snicm void
99883e83a91Snicm input_parse_screen(struct input_ctx *ictx, struct screen *s,
99983e83a91Snicm     screen_write_init_ctx_cb cb, void *arg, u_char *buf, size_t len)
100029ebed37Snicm {
100129ebed37Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
100229ebed37Snicm 
100329ebed37Snicm 	if (len == 0)
100429ebed37Snicm 		return;
100529ebed37Snicm 
100683e83a91Snicm 	screen_write_start_callback(sctx, s, cb, arg);
100729ebed37Snicm 	input_parse(ictx, buf, len);
10083248c880Snicm 	screen_write_stop(sctx);
1009311827fbSnicm }
1010311827fbSnicm 
1011dee808c1Snicm /* Split the parameter list (if any). */
1012413e5e52Snicm static int
1013dee808c1Snicm input_split(struct input_ctx *ictx)
1014311827fbSnicm {
1015dee808c1Snicm 	const char		*errstr;
1016dee808c1Snicm 	char			*ptr, *out;
1017902fbd84Snicm 	struct input_param	*ip;
1018902fbd84Snicm 	u_int			 i;
1019dee808c1Snicm 
1020902fbd84Snicm 	for (i = 0; i < ictx->param_list_len; i++) {
1021902fbd84Snicm 		if (ictx->param_list[i].type == INPUT_STRING)
1022902fbd84Snicm 			free(ictx->param_list[i].str);
1023902fbd84Snicm 	}
1024dee808c1Snicm 	ictx->param_list_len = 0;
1025902fbd84Snicm 
1026dee808c1Snicm 	if (ictx->param_len == 0)
1027dee808c1Snicm 		return (0);
1028902fbd84Snicm 	ip = &ictx->param_list[0];
1029dee808c1Snicm 
1030dee808c1Snicm 	ptr = ictx->param_buf;
1031dee808c1Snicm 	while ((out = strsep(&ptr, ";")) != NULL) {
1032dee808c1Snicm 		if (*out == '\0')
1033902fbd84Snicm 			ip->type = INPUT_MISSING;
1034311827fbSnicm 		else {
1035902fbd84Snicm 			if (strchr(out, ':') != NULL) {
1036902fbd84Snicm 				ip->type = INPUT_STRING;
1037902fbd84Snicm 				ip->str = xstrdup(out);
1038902fbd84Snicm 			} else {
1039902fbd84Snicm 				ip->type = INPUT_NUMBER;
1040902fbd84Snicm 				ip->num = strtonum(out, 0, INT_MAX, &errstr);
1041dee808c1Snicm 				if (errstr != NULL)
1042dee808c1Snicm 					return (-1);
1043311827fbSnicm 			}
1044902fbd84Snicm 		}
1045902fbd84Snicm 		ip = &ictx->param_list[++ictx->param_list_len];
1046dee808c1Snicm 		if (ictx->param_list_len == nitems(ictx->param_list))
1047dee808c1Snicm 			return (-1);
1048311827fbSnicm 	}
1049311827fbSnicm 
1050902fbd84Snicm 	for (i = 0; i < ictx->param_list_len; i++) {
1051902fbd84Snicm 		ip = &ictx->param_list[i];
1052902fbd84Snicm 		if (ip->type == INPUT_MISSING)
1053902fbd84Snicm 			log_debug("parameter %u: missing", i);
1054902fbd84Snicm 		else if (ip->type == INPUT_STRING)
1055902fbd84Snicm 			log_debug("parameter %u: string %s", i, ip->str);
1056902fbd84Snicm 		else if (ip->type == INPUT_NUMBER)
1057902fbd84Snicm 			log_debug("parameter %u: number %d", i, ip->num);
1058902fbd84Snicm 	}
1059902fbd84Snicm 
1060dee808c1Snicm 	return (0);
1061311827fbSnicm }
1062311827fbSnicm 
10635ea6a24aSnicm /* Get an argument or return default value. */
1064413e5e52Snicm static int
1065dee808c1Snicm input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
1066311827fbSnicm {
1067902fbd84Snicm 	struct input_param	*ip;
1068dee808c1Snicm 	int			 retval;
1069dee808c1Snicm 
1070dee808c1Snicm 	if (validx >= ictx->param_list_len)
1071dee808c1Snicm 	    return (defval);
1072902fbd84Snicm 	ip = &ictx->param_list[validx];
1073902fbd84Snicm 	if (ip->type == INPUT_MISSING)
1074dee808c1Snicm 		return (defval);
1075902fbd84Snicm 	if (ip->type == INPUT_STRING)
1076902fbd84Snicm 		return (-1);
1077902fbd84Snicm 	retval = ip->num;
1078dee808c1Snicm 	if (retval < minval)
1079dee808c1Snicm 		return (minval);
1080dee808c1Snicm 	return (retval);
1081311827fbSnicm }
1082311827fbSnicm 
1083dee808c1Snicm /* Reply to terminal query. */
1084413e5e52Snicm static void
1085dee808c1Snicm input_reply(struct input_ctx *ictx, const char *fmt, ...)
1086311827fbSnicm {
1087cf6b0e8fSnicm 	struct bufferevent	*bev = ictx->event;
1088dee808c1Snicm 	va_list			 ap;
1089dee808c1Snicm 	char			*reply;
1090dee808c1Snicm 
109116be08e6Snicm 	if (bev == NULL)
109216be08e6Snicm 		return;
109316be08e6Snicm 
1094dee808c1Snicm 	va_start(ap, fmt);
1095543b06d2Snicm 	xvasprintf(&reply, fmt, ap);
1096dee808c1Snicm 	va_end(ap);
1097dee808c1Snicm 
1098d21788ceSnicm 	log_debug("%s: %s", __func__, reply);
1099cf6b0e8fSnicm 	bufferevent_write(bev, reply, strlen(reply));
11007d053cf9Snicm 	free(reply);
1101311827fbSnicm }
1102311827fbSnicm 
1103dee808c1Snicm /* Clear saved state. */
1104413e5e52Snicm static void
1105dee808c1Snicm input_clear(struct input_ctx *ictx)
1106311827fbSnicm {
11075842cea5Snicm 	event_del(&ictx->timer);
11085842cea5Snicm 
1109dee808c1Snicm 	*ictx->interm_buf = '\0';
1110dee808c1Snicm 	ictx->interm_len = 0;
1111311827fbSnicm 
1112dee808c1Snicm 	*ictx->param_buf = '\0';
1113dee808c1Snicm 	ictx->param_len = 0;
1114dee808c1Snicm 
11154e829c14Snicm 	*ictx->input_buf = '\0';
11164e829c14Snicm 	ictx->input_len = 0;
11174e829c14Snicm 
111890866723Snicm 	ictx->input_end = INPUT_END_ST;
111990866723Snicm 
1120dee808c1Snicm 	ictx->flags &= ~INPUT_DISCARD;
1121311827fbSnicm }
1122311827fbSnicm 
11232b3ef6e2Snicm /* Reset for ground state. */
1124413e5e52Snicm static void
11252b3ef6e2Snicm input_ground(struct input_ctx *ictx)
11262b3ef6e2Snicm {
11275842cea5Snicm 	event_del(&ictx->timer);
11282b3ef6e2Snicm 	evbuffer_drain(ictx->since_ground, EVBUFFER_LENGTH(ictx->since_ground));
11292b3ef6e2Snicm 
11302b3ef6e2Snicm 	if (ictx->input_space > INPUT_BUF_START) {
11312b3ef6e2Snicm 		ictx->input_space = INPUT_BUF_START;
113264cf113cSnicm 		ictx->input_buf = xrealloc(ictx->input_buf, INPUT_BUF_START);
11332b3ef6e2Snicm 	}
11342b3ef6e2Snicm }
11352b3ef6e2Snicm 
1136dee808c1Snicm /* Output this character to the screen. */
1137413e5e52Snicm static int
1138dee808c1Snicm input_print(struct input_ctx *ictx)
1139311827fbSnicm {
11403248c880Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
1141c2a06f72Snicm 	int			 set;
1142c2a06f72Snicm 
1143e51b0e35Snicm 	ictx->utf8started = 0; /* can't be valid UTF-8 */
1144e51b0e35Snicm 
1145c2a06f72Snicm 	set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
1146c2a06f72Snicm 	if (set == 1)
1147c2a06f72Snicm 		ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
1148c2a06f72Snicm 	else
1149c2a06f72Snicm 		ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1150e931849fSnicm 	utf8_set(&ictx->cell.cell.data, ictx->ch);
11513248c880Snicm 	screen_write_collect_add(sctx, &ictx->cell.cell);
115280c8bfd3Snicm 
115380c8bfd3Snicm 	utf8_copy(&ictx->last, &ictx->cell.cell.data);
115480c8bfd3Snicm 	ictx->flags |= INPUT_LAST;
1155c2a06f72Snicm 
1156c2a06f72Snicm 	ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
1157dee808c1Snicm 
1158dee808c1Snicm 	return (0);
1159311827fbSnicm }
1160311827fbSnicm 
1161dee808c1Snicm /* Collect intermediate string. */
1162413e5e52Snicm static int
1163dee808c1Snicm input_intermediate(struct input_ctx *ictx)
1164311827fbSnicm {
1165dee808c1Snicm 	if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
1166dee808c1Snicm 		ictx->flags |= INPUT_DISCARD;
1167dee808c1Snicm 	else {
1168dee808c1Snicm 		ictx->interm_buf[ictx->interm_len++] = ictx->ch;
1169dee808c1Snicm 		ictx->interm_buf[ictx->interm_len] = '\0';
1170dee808c1Snicm 	}
1171311827fbSnicm 
1172dee808c1Snicm 	return (0);
1173dee808c1Snicm }
1174311827fbSnicm 
1175dee808c1Snicm /* Collect parameter string. */
1176413e5e52Snicm static int
1177dee808c1Snicm input_parameter(struct input_ctx *ictx)
1178dee808c1Snicm {
1179dee808c1Snicm 	if (ictx->param_len == (sizeof ictx->param_buf) - 1)
1180dee808c1Snicm 		ictx->flags |= INPUT_DISCARD;
1181dee808c1Snicm 	else {
1182dee808c1Snicm 		ictx->param_buf[ictx->param_len++] = ictx->ch;
1183dee808c1Snicm 		ictx->param_buf[ictx->param_len] = '\0';
1184dee808c1Snicm 	}
1185dee808c1Snicm 
1186dee808c1Snicm 	return (0);
1187dee808c1Snicm }
1188dee808c1Snicm 
1189dee808c1Snicm /* Collect input string. */
1190413e5e52Snicm static int
1191dee808c1Snicm input_input(struct input_ctx *ictx)
1192dee808c1Snicm {
11932b3ef6e2Snicm 	size_t available;
11942b3ef6e2Snicm 
11952b3ef6e2Snicm 	available = ictx->input_space;
11962b3ef6e2Snicm 	while (ictx->input_len + 1 >= available) {
11972b3ef6e2Snicm 		available *= 2;
1198*d5f1c1a5Snicm 		if (available > input_buffer_size) {
1199dee808c1Snicm 			ictx->flags |= INPUT_DISCARD;
12002b3ef6e2Snicm 			return (0);
12012b3ef6e2Snicm 		}
120264cf113cSnicm 		ictx->input_buf = xrealloc(ictx->input_buf, available);
12032b3ef6e2Snicm 		ictx->input_space = available;
12042b3ef6e2Snicm 	}
1205dee808c1Snicm 	ictx->input_buf[ictx->input_len++] = ictx->ch;
1206dee808c1Snicm 	ictx->input_buf[ictx->input_len] = '\0';
1207dee808c1Snicm 
1208dee808c1Snicm 	return (0);
1209dee808c1Snicm }
1210dee808c1Snicm 
1211dee808c1Snicm /* Execute C0 control sequence. */
1212413e5e52Snicm static int
1213dee808c1Snicm input_c0_dispatch(struct input_ctx *ictx)
1214dee808c1Snicm {
1215dee808c1Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
1216dee808c1Snicm 	struct window_pane	*wp = ictx->wp;
1217dee808c1Snicm 	struct screen		*s = sctx->s;
121802d75531Snicm 	struct grid_cell	 gc, first_gc;
121902d75531Snicm 	u_int			 cx = s->cx, line = s->cy + s->grid->hsize;
122002d75531Snicm 	u_int			 width;
122102d75531Snicm 	int			 has_content = 0;
1222dee808c1Snicm 
1223e51b0e35Snicm 	ictx->utf8started = 0; /* can't be valid UTF-8 */
1224e51b0e35Snicm 
12252223f47bSnicm 	log_debug("%s: '%c'", __func__, ictx->ch);
1226dee808c1Snicm 
1227dee808c1Snicm 	switch (ictx->ch) {
1228dee808c1Snicm 	case '\000':	/* NUL */
1229311827fbSnicm 		break;
1230dee808c1Snicm 	case '\007':	/* BEL */
123129ebed37Snicm 		if (wp != NULL)
123281fe4598Snicm 			alerts_queue(wp->window, WINDOW_BELL);
1233311827fbSnicm 		break;
1234311827fbSnicm 	case '\010':	/* BS */
1235dee808c1Snicm 		screen_write_backspace(sctx);
1236a9a097e5Snicm 		break;
1237dee808c1Snicm 	case '\011':	/* HT */
123814e0d2d2Snicm 		/* Don't tab beyond the end of the line. */
123914e0d2d2Snicm 		if (s->cx >= screen_size_x(s) - 1)
124014e0d2d2Snicm 			break;
124114e0d2d2Snicm 
124214e0d2d2Snicm 		/* Find the next tab point, or use the last column if none. */
124302d75531Snicm 		grid_get_cell(s->grid, s->cx, line, &first_gc);
124414e0d2d2Snicm 		do {
124502d75531Snicm 			if (!has_content) {
124602d75531Snicm 				grid_get_cell(s->grid, cx, line, &gc);
124702d75531Snicm 				if (gc.data.size != 1 ||
124802d75531Snicm 				    *gc.data.data != ' ' ||
124902d75531Snicm 				    !grid_cells_look_equal(&gc, &first_gc))
125002d75531Snicm 					has_content = 1;
125102d75531Snicm 			}
125202d75531Snicm 			cx++;
125302d75531Snicm 			if (bit_test(s->tabs, cx))
125414e0d2d2Snicm 				break;
125502d75531Snicm 		} while (cx < screen_size_x(s) - 1);
125602d75531Snicm 
125702d75531Snicm 		width = cx - s->cx;
125802d75531Snicm 		if (has_content || width > sizeof gc.data.data)
125902d75531Snicm 			s->cx = cx;
126002d75531Snicm 		else {
126102d75531Snicm 			grid_get_cell(s->grid, s->cx, line, &gc);
126202d75531Snicm 			grid_set_tab(&gc, width);
126302d75531Snicm 			screen_write_collect_add(sctx, &gc);
126402d75531Snicm 		}
1265311827fbSnicm 		break;
1266dee808c1Snicm 	case '\012':	/* LF */
12678ba522d1Snicm 	case '\013':	/* VT */
1268dee808c1Snicm 	case '\014':	/* FF */
12696d5c64a0Snicm 		screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1270aab3c1a6Snicm 		if (s->mode & MODE_CRLF)
1271aab3c1a6Snicm 			screen_write_carriagereturn(sctx);
1272a9a097e5Snicm 		break;
1273dee808c1Snicm 	case '\015':	/* CR */
1274dee808c1Snicm 		screen_write_carriagereturn(sctx);
1275a9a097e5Snicm 		break;
1276311827fbSnicm 	case '\016':	/* SO */
1277c2a06f72Snicm 		ictx->cell.set = 1;
1278311827fbSnicm 		break;
1279311827fbSnicm 	case '\017':	/* SI */
1280c2a06f72Snicm 		ictx->cell.set = 0;
1281311827fbSnicm 		break;
1282311827fbSnicm 	default:
1283dee808c1Snicm 		log_debug("%s: unknown '%c'", __func__, ictx->ch);
1284311827fbSnicm 		break;
1285311827fbSnicm 	}
1286dee808c1Snicm 
128780c8bfd3Snicm 	ictx->flags &= ~INPUT_LAST;
1288dee808c1Snicm 	return (0);
1289311827fbSnicm }
1290311827fbSnicm 
1291dee808c1Snicm /* Execute escape sequence. */
1292413e5e52Snicm static int
1293dee808c1Snicm input_esc_dispatch(struct input_ctx *ictx)
1294311827fbSnicm {
1295dee808c1Snicm 	struct screen_write_ctx		*sctx = &ictx->ctx;
1296dee808c1Snicm 	struct screen			*s = sctx->s;
1297dee808c1Snicm 	struct input_table_entry	*entry;
129814e0d2d2Snicm 
1299dee808c1Snicm 	if (ictx->flags & INPUT_DISCARD)
1300dee808c1Snicm 		return (0);
1301dee808c1Snicm 	log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1302311827fbSnicm 
1303dee808c1Snicm 	entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
1304dee808c1Snicm 	    sizeof input_esc_table[0], input_table_compare);
1305dee808c1Snicm 	if (entry == NULL) {
1306dee808c1Snicm 		log_debug("%s: unknown '%c'", __func__, ictx->ch);
1307dee808c1Snicm 		return (0);
1308dee808c1Snicm 	}
1309dee808c1Snicm 
1310dee808c1Snicm 	switch (entry->type) {
1311dee808c1Snicm 	case INPUT_ESC_RIS:
131233a1e283Snicm 		colour_palette_clear(ictx->palette);
1313c2a06f72Snicm 		input_reset_cell(ictx);
131478a50ec3Snicm 		screen_write_reset(sctx);
131533a1e283Snicm 		screen_write_fullredraw(sctx);
1316b18cc82cSnicm 		break;
1317dee808c1Snicm 	case INPUT_ESC_IND:
13186d5c64a0Snicm 		screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1319311827fbSnicm 		break;
1320dee808c1Snicm 	case INPUT_ESC_NEL:
1321dee808c1Snicm 		screen_write_carriagereturn(sctx);
13226d5c64a0Snicm 		screen_write_linefeed(sctx, 0, ictx->cell.cell.bg);
1323dee808c1Snicm 		break;
1324dee808c1Snicm 	case INPUT_ESC_HTS:
132514e0d2d2Snicm 		if (s->cx < screen_size_x(s))
132614e0d2d2Snicm 			bit_set(s->tabs, s->cx);
132714e0d2d2Snicm 		break;
1328dee808c1Snicm 	case INPUT_ESC_RI:
13296d5c64a0Snicm 		screen_write_reverseindex(sctx, ictx->cell.cell.bg);
1330311827fbSnicm 		break;
1331dee808c1Snicm 	case INPUT_ESC_DECKPAM:
13323699ed24Snicm 		screen_write_mode_set(sctx, MODE_KKEYPAD);
1333311827fbSnicm 		break;
1334dee808c1Snicm 	case INPUT_ESC_DECKPNM:
13353699ed24Snicm 		screen_write_mode_clear(sctx, MODE_KKEYPAD);
1336dee808c1Snicm 		break;
1337dee808c1Snicm 	case INPUT_ESC_DECSC:
13385c6c7001Snicm 		input_save_state(ictx);
1339dee808c1Snicm 		break;
1340dee808c1Snicm 	case INPUT_ESC_DECRC:
13415c6c7001Snicm 		input_restore_state(ictx);
1342dee808c1Snicm 		break;
1343dee808c1Snicm 	case INPUT_ESC_DECALN:
1344dee808c1Snicm 		screen_write_alignmenttest(sctx);
1345dee808c1Snicm 		break;
1346c2a06f72Snicm 	case INPUT_ESC_SCSG0_ON:
1347c2a06f72Snicm 		ictx->cell.g0set = 1;
1348dee808c1Snicm 		break;
1349c2a06f72Snicm 	case INPUT_ESC_SCSG0_OFF:
1350c2a06f72Snicm 		ictx->cell.g0set = 0;
1351c2a06f72Snicm 		break;
1352c2a06f72Snicm 	case INPUT_ESC_SCSG1_ON:
1353c2a06f72Snicm 		ictx->cell.g1set = 1;
1354c2a06f72Snicm 		break;
1355c2a06f72Snicm 	case INPUT_ESC_SCSG1_OFF:
1356c2a06f72Snicm 		ictx->cell.g1set = 0;
1357311827fbSnicm 		break;
1358e16c1698Snicm 	case INPUT_ESC_ST:
1359e16c1698Snicm 		/* ST terminates OSC but the state transition already did it. */
1360e16c1698Snicm 		break;
1361311827fbSnicm 	}
1362dee808c1Snicm 
136380c8bfd3Snicm 	ictx->flags &= ~INPUT_LAST;
1364dee808c1Snicm 	return (0);
1365311827fbSnicm }
1366311827fbSnicm 
1367dee808c1Snicm /* Execute control sequence. */
1368413e5e52Snicm static int
1369dee808c1Snicm input_csi_dispatch(struct input_ctx *ictx)
1370311827fbSnicm {
1371dee808c1Snicm 	struct screen_write_ctx	       *sctx = &ictx->ctx;
1372dee808c1Snicm 	struct screen		       *s = sctx->s;
1373dee808c1Snicm 	struct input_table_entry       *entry;
1374aaa8edadSnicm 	int				i, n, m, ek, set;
1375902fbd84Snicm 	u_int				cx, bg = ictx->cell.cell.bg;
1376311827fbSnicm 
1377dee808c1Snicm 	if (ictx->flags & INPUT_DISCARD)
1378dee808c1Snicm 		return (0);
13795beb4badSnicm 
1380e0697ebcSnicm 	log_debug("%s: '%c' \"%s\" \"%s\"", __func__, ictx->ch,
1381e0697ebcSnicm 	    ictx->interm_buf, ictx->param_buf);
1382311827fbSnicm 
13835beb4badSnicm 	if (input_split(ictx) != 0)
13845beb4badSnicm 		return (0);
13855beb4badSnicm 
1386dee808c1Snicm 	entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1387dee808c1Snicm 	    sizeof input_csi_table[0], input_table_compare);
1388dee808c1Snicm 	if (entry == NULL) {
1389dee808c1Snicm 		log_debug("%s: unknown '%c'", __func__, ictx->ch);
1390dee808c1Snicm 		return (0);
1391311827fbSnicm 	}
1392311827fbSnicm 
1393dee808c1Snicm 	switch (entry->type) {
1394dee808c1Snicm 	case INPUT_CSI_CBT:
1395f4b42ab9Snicm 		/* Find the previous tab point, n times. */
1396dfeb6f48Snicm 		cx = s->cx;
1397dfeb6f48Snicm 		if (cx > screen_size_x(s) - 1)
1398dfeb6f48Snicm 			cx = screen_size_x(s) - 1;
1399dee808c1Snicm 		n = input_get(ictx, 0, 1, 1);
1400902fbd84Snicm 		if (n == -1)
1401902fbd84Snicm 			break;
1402dfeb6f48Snicm 		while (cx > 0 && n-- > 0) {
1403f4b42ab9Snicm 			do
1404dfeb6f48Snicm 				cx--;
1405dfeb6f48Snicm 			while (cx > 0 && !bit_test(s->tabs, cx));
1406f4b42ab9Snicm 		}
1407dfeb6f48Snicm 		s->cx = cx;
1408dee808c1Snicm 		break;
1409dee808c1Snicm 	case INPUT_CSI_CUB:
1410902fbd84Snicm 		n = input_get(ictx, 0, 1, 1);
1411902fbd84Snicm 		if (n != -1)
1412902fbd84Snicm 			screen_write_cursorleft(sctx, n);
1413dee808c1Snicm 		break;
1414dee808c1Snicm 	case INPUT_CSI_CUD:
1415902fbd84Snicm 		n = input_get(ictx, 0, 1, 1);
1416902fbd84Snicm 		if (n != -1)
1417902fbd84Snicm 			screen_write_cursordown(sctx, n);
1418dee808c1Snicm 		break;
1419dee808c1Snicm 	case INPUT_CSI_CUF:
1420902fbd84Snicm 		n = input_get(ictx, 0, 1, 1);
1421902fbd84Snicm 		if (n != -1)
1422902fbd84Snicm 			screen_write_cursorright(sctx, n);
1423dee808c1Snicm 		break;
1424dee808c1Snicm 	case INPUT_CSI_CUP:
1425dee808c1Snicm 		n = input_get(ictx, 0, 1, 1);
1426dee808c1Snicm 		m = input_get(ictx, 1, 1, 1);
1427902fbd84Snicm 		if (n != -1 && m != -1)
14285c6c7001Snicm 			screen_write_cursormove(sctx, m - 1, n - 1, 1);
1429dee808c1Snicm 		break;
1430dcf80b09Snicm 	case INPUT_CSI_MODSET:
1431dcf80b09Snicm 		n = input_get(ictx, 0, 0, 0);
143254ec0e18Snicm 		if (n != 4)
14330465bfa0Snicm 			break;
143454ec0e18Snicm 		m = input_get(ictx, 1, 0, 0);
143554ec0e18Snicm 
143654ec0e18Snicm 		/*
143754ec0e18Snicm 		 * Set the extended key reporting mode as per the client
143854ec0e18Snicm 		 * request, unless "extended-keys" is set to "off".
143954ec0e18Snicm 		 */
144054ec0e18Snicm 		ek = options_get_number(global_options, "extended-keys");
144154ec0e18Snicm 		if (ek == 0)
144254ec0e18Snicm 			break;
144354ec0e18Snicm 		screen_write_mode_clear(sctx, EXTENDED_KEY_MODES);
144454ec0e18Snicm 		if (m == 2)
1445719f5715Snicm 			screen_write_mode_set(sctx, MODE_KEYS_EXTENDED_2);
144654ec0e18Snicm 		else if (m == 1 || ek == 2)
144754ec0e18Snicm 			screen_write_mode_set(sctx, MODE_KEYS_EXTENDED);
1448dcf80b09Snicm 		break;
1449dcf80b09Snicm 	case INPUT_CSI_MODOFF:
1450dcf80b09Snicm 		n = input_get(ictx, 0, 0, 0);
145154ec0e18Snicm 		if (n != 4)
145254ec0e18Snicm 			break;
145354ec0e18Snicm 
1454719f5715Snicm 		/*
145554ec0e18Snicm 		 * Clear the extended key reporting mode as per the client
145654ec0e18Snicm 		 * request, unless "extended-keys always" forces into mode 1.
1457719f5715Snicm 		 */
1458719f5715Snicm 		screen_write_mode_clear(sctx,
1459719f5715Snicm 		    MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2);
146054ec0e18Snicm 		if (options_get_number(global_options, "extended-keys") == 2)
146154ec0e18Snicm 			screen_write_mode_set(sctx, MODE_KEYS_EXTENDED);
1462dcf80b09Snicm 		break;
1463c8af5297Snicm 	case INPUT_CSI_WINOPS:
1464c8af5297Snicm 		input_csi_dispatch_winops(ictx);
1465c8af5297Snicm 		break;
1466dee808c1Snicm 	case INPUT_CSI_CUU:
1467902fbd84Snicm 		n = input_get(ictx, 0, 1, 1);
1468902fbd84Snicm 		if (n != -1)
1469902fbd84Snicm 			screen_write_cursorup(sctx, n);
1470dee808c1Snicm 		break;
147103fa59bdSnicm 	case INPUT_CSI_CNL:
1472902fbd84Snicm 		n = input_get(ictx, 0, 1, 1);
1473902fbd84Snicm 		if (n != -1) {
147403fa59bdSnicm 			screen_write_carriagereturn(sctx);
1475902fbd84Snicm 			screen_write_cursordown(sctx, n);
1476902fbd84Snicm 		}
147703fa59bdSnicm 		break;
147803fa59bdSnicm 	case INPUT_CSI_CPL:
1479902fbd84Snicm 		n = input_get(ictx, 0, 1, 1);
1480902fbd84Snicm 		if (n != -1) {
148103fa59bdSnicm 			screen_write_carriagereturn(sctx);
1482902fbd84Snicm 			screen_write_cursorup(sctx, n);
1483902fbd84Snicm 		}
148403fa59bdSnicm 		break;
1485dee808c1Snicm 	case INPUT_CSI_DA:
1486dee808c1Snicm 		switch (input_get(ictx, 0, 0, 0)) {
1487902fbd84Snicm 		case -1:
1488902fbd84Snicm 			break;
148914e0d2d2Snicm 		case 0:
1490dee808c1Snicm 			input_reply(ictx, "\033[?1;2c");
1491953d773cSnicm 			break;
1492311827fbSnicm 		default:
1493dee808c1Snicm 			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1494311827fbSnicm 			break;
1495311827fbSnicm 		}
1496dee808c1Snicm 		break;
1497b9cdec04Snicm 	case INPUT_CSI_DA_TWO:
1498b9cdec04Snicm 		switch (input_get(ictx, 0, 0, 0)) {
1499902fbd84Snicm 		case -1:
1500902fbd84Snicm 			break;
1501b9cdec04Snicm 		case 0:
1502a9497364Snicm 			input_reply(ictx, "\033[>84;0;0c");
1503b9cdec04Snicm 			break;
1504b9cdec04Snicm 		default:
1505b9cdec04Snicm 			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1506b9cdec04Snicm 			break;
1507b9cdec04Snicm 		}
1508b9cdec04Snicm 		break;
1509f752bf02Snicm 	case INPUT_CSI_ECH:
1510902fbd84Snicm 		n = input_get(ictx, 0, 1, 1);
1511902fbd84Snicm 		if (n != -1)
1512902fbd84Snicm 			screen_write_clearcharacter(sctx, n, bg);
1513f752bf02Snicm 		break;
1514dee808c1Snicm 	case INPUT_CSI_DCH:
1515902fbd84Snicm 		n = input_get(ictx, 0, 1, 1);
1516902fbd84Snicm 		if (n != -1)
1517902fbd84Snicm 			screen_write_deletecharacter(sctx, n, bg);
1518dee808c1Snicm 		break;
1519dee808c1Snicm 	case INPUT_CSI_DECSTBM:
1520dee808c1Snicm 		n = input_get(ictx, 0, 1, 1);
1521dee808c1Snicm 		m = input_get(ictx, 1, 1, screen_size_y(s));
1522902fbd84Snicm 		if (n != -1 && m != -1)
1523dee808c1Snicm 			screen_write_scrollregion(sctx, n - 1, m - 1);
1524dee808c1Snicm 		break;
1525dee808c1Snicm 	case INPUT_CSI_DL:
1526902fbd84Snicm 		n = input_get(ictx, 0, 1, 1);
1527902fbd84Snicm 		if (n != -1)
1528902fbd84Snicm 			screen_write_deleteline(sctx, n, bg);
1529dee808c1Snicm 		break;
1530dee808c1Snicm 	case INPUT_CSI_DSR:
1531dee808c1Snicm 		switch (input_get(ictx, 0, 0, 0)) {
1532902fbd84Snicm 		case -1:
1533902fbd84Snicm 			break;
1534dee808c1Snicm 		case 5:
1535dee808c1Snicm 			input_reply(ictx, "\033[0n");
1536dee808c1Snicm 			break;
1537dee808c1Snicm 		case 6:
1538dee808c1Snicm 			input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1539dee808c1Snicm 			break;
1540dee808c1Snicm 		default:
1541dee808c1Snicm 			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1542dee808c1Snicm 			break;
1543dee808c1Snicm 		}
1544dee808c1Snicm 		break;
1545dee808c1Snicm 	case INPUT_CSI_ED:
1546dee808c1Snicm 		switch (input_get(ictx, 0, 0, 0)) {
1547902fbd84Snicm 		case -1:
1548902fbd84Snicm 			break;
1549dee808c1Snicm 		case 0:
1550902fbd84Snicm 			screen_write_clearendofscreen(sctx, bg);
1551dee808c1Snicm 			break;
1552dee808c1Snicm 		case 1:
1553902fbd84Snicm 			screen_write_clearstartofscreen(sctx, bg);
1554dee808c1Snicm 			break;
1555dee808c1Snicm 		case 2:
1556902fbd84Snicm 			screen_write_clearscreen(sctx, bg);
1557dee808c1Snicm 			break;
1558786c44dcSnicm 		case 3:
1559902fbd84Snicm 			if (input_get(ictx, 1, 0, 0) == 0) {
1560786c44dcSnicm 				/*
1561786c44dcSnicm 				 * Linux console extension to clear history
1562786c44dcSnicm 				 * (for example before locking the screen).
1563786c44dcSnicm 				 */
1564786c44dcSnicm 				screen_write_clearhistory(sctx);
1565786c44dcSnicm 			}
1566786c44dcSnicm 			break;
1567dee808c1Snicm 		default:
1568dee808c1Snicm 			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1569dee808c1Snicm 			break;
1570dee808c1Snicm 		}
1571dee808c1Snicm 		break;
1572dee808c1Snicm 	case INPUT_CSI_EL:
1573dee808c1Snicm 		switch (input_get(ictx, 0, 0, 0)) {
1574902fbd84Snicm 		case -1:
1575902fbd84Snicm 			break;
1576dee808c1Snicm 		case 0:
1577902fbd84Snicm 			screen_write_clearendofline(sctx, bg);
1578dee808c1Snicm 			break;
1579dee808c1Snicm 		case 1:
1580902fbd84Snicm 			screen_write_clearstartofline(sctx, bg);
1581dee808c1Snicm 			break;
1582dee808c1Snicm 		case 2:
1583902fbd84Snicm 			screen_write_clearline(sctx, bg);
1584dee808c1Snicm 			break;
1585dee808c1Snicm 		default:
1586dee808c1Snicm 			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1587dee808c1Snicm 			break;
1588dee808c1Snicm 		}
1589dee808c1Snicm 		break;
1590dee808c1Snicm 	case INPUT_CSI_HPA:
1591dee808c1Snicm 		n = input_get(ictx, 0, 1, 1);
1592902fbd84Snicm 		if (n != -1)
1593edcf3982Snicm 			screen_write_cursormove(sctx, n - 1, -1, 1);
1594dee808c1Snicm 		break;
1595dee808c1Snicm 	case INPUT_CSI_ICH:
1596902fbd84Snicm 		n = input_get(ictx, 0, 1, 1);
1597902fbd84Snicm 		if (n != -1)
1598902fbd84Snicm 			screen_write_insertcharacter(sctx, n, bg);
1599dee808c1Snicm 		break;
1600dee808c1Snicm 	case INPUT_CSI_IL:
1601902fbd84Snicm 		n = input_get(ictx, 0, 1, 1);
1602902fbd84Snicm 		if (n != -1)
1603902fbd84Snicm 			screen_write_insertline(sctx, n, bg);
1604dee808c1Snicm 		break;
160589444e08Snicm 	case INPUT_CSI_REP:
1606902fbd84Snicm 		n = input_get(ictx, 0, 1, 1);
1607902fbd84Snicm 		if (n == -1)
1608902fbd84Snicm 			break;
1609902fbd84Snicm 
16104d4cc167Snicm 		m = screen_size_x(s) - s->cx;
16114d4cc167Snicm 		if (n > m)
16124d4cc167Snicm 			n = m;
16134d4cc167Snicm 
161480c8bfd3Snicm 		if (~ictx->flags & INPUT_LAST)
161589444e08Snicm 			break;
161689444e08Snicm 
1617aaa8edadSnicm 		set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
1618aaa8edadSnicm 		if (set == 1)
1619aaa8edadSnicm 			ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
1620aaa8edadSnicm 		else
1621aaa8edadSnicm 			ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
162280c8bfd3Snicm 		utf8_copy(&ictx->cell.cell.data, &ictx->last);
162389444e08Snicm 		for (i = 0; i < n; i++)
162480c8bfd3Snicm 			screen_write_collect_add(sctx, &ictx->cell.cell);
162589444e08Snicm 		break;
1626dbbae13bSnicm 	case INPUT_CSI_RCP:
16275c6c7001Snicm 		input_restore_state(ictx);
1628dbbae13bSnicm 		break;
1629dee808c1Snicm 	case INPUT_CSI_RM:
163070988a14Snicm 		input_csi_dispatch_rm(ictx);
163170988a14Snicm 		break;
163270988a14Snicm 	case INPUT_CSI_RM_PRIVATE:
163370988a14Snicm 		input_csi_dispatch_rm_private(ictx);
163470988a14Snicm 		break;
163570988a14Snicm 	case INPUT_CSI_SCP:
16365c6c7001Snicm 		input_save_state(ictx);
163770988a14Snicm 		break;
163870988a14Snicm 	case INPUT_CSI_SGR:
163970988a14Snicm 		input_csi_dispatch_sgr(ictx);
164070988a14Snicm 		break;
164170988a14Snicm 	case INPUT_CSI_SM:
164270988a14Snicm 		input_csi_dispatch_sm(ictx);
164370988a14Snicm 		break;
164470988a14Snicm 	case INPUT_CSI_SM_PRIVATE:
164570988a14Snicm 		input_csi_dispatch_sm_private(ictx);
164670988a14Snicm 		break;
16477b23d14cSnicm 	case INPUT_CSI_SM_GRAPHICS:
16487b23d14cSnicm 		input_csi_dispatch_sm_graphics(ictx);
16497b23d14cSnicm 		break;
1650f0063641Snicm 	case INPUT_CSI_SU:
1651902fbd84Snicm 		n = input_get(ictx, 0, 1, 1);
1652902fbd84Snicm 		if (n != -1)
1653902fbd84Snicm 			screen_write_scrollup(sctx, n, bg);
1654f0063641Snicm 		break;
1655fa32c33cSnicm 	case INPUT_CSI_SD:
1656fa32c33cSnicm 		n = input_get(ictx, 0, 1, 1);
1657fa32c33cSnicm 		if (n != -1)
1658fa32c33cSnicm 			screen_write_scrolldown(sctx, n, bg);
1659fa32c33cSnicm 		break;
166070988a14Snicm 	case INPUT_CSI_TBC:
166170988a14Snicm 		switch (input_get(ictx, 0, 0, 0)) {
1662902fbd84Snicm 		case -1:
1663902fbd84Snicm 			break;
166470988a14Snicm 		case 0:
166570988a14Snicm 			if (s->cx < screen_size_x(s))
166670988a14Snicm 				bit_clear(s->tabs, s->cx);
166770988a14Snicm 			break;
166870988a14Snicm 		case 3:
166970988a14Snicm 			bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
167070988a14Snicm 			break;
167170988a14Snicm 		default:
167270988a14Snicm 			log_debug("%s: unknown '%c'", __func__, ictx->ch);
167370988a14Snicm 			break;
167470988a14Snicm 		}
167570988a14Snicm 		break;
167670988a14Snicm 	case INPUT_CSI_VPA:
167770988a14Snicm 		n = input_get(ictx, 0, 1, 1);
1678902fbd84Snicm 		if (n != -1)
1679edcf3982Snicm 			screen_write_cursormove(sctx, -1, n - 1, 1);
168070988a14Snicm 		break;
168170988a14Snicm 	case INPUT_CSI_DECSCUSR:
168270988a14Snicm 		n = input_get(ictx, 0, 0, 0);
1683902fbd84Snicm 		if (n != -1)
16846a238659Snicm 			screen_set_cursor_style(n, &s->cstyle, &s->mode);
168570988a14Snicm 		break;
1686ecd9db25Snicm 	case INPUT_CSI_XDA:
1687ecd9db25Snicm 		n = input_get(ictx, 0, 0, 0);
1688dcf80b09Snicm 		if (n == 0)
1689ecd9db25Snicm 			input_reply(ictx, "\033P>|tmux %s\033\\", getversion());
1690ecd9db25Snicm 		break;
1691ecd9db25Snicm 
169270988a14Snicm 	}
169370988a14Snicm 
169480c8bfd3Snicm 	ictx->flags &= ~INPUT_LAST;
169570988a14Snicm 	return (0);
169670988a14Snicm }
169770988a14Snicm 
169870988a14Snicm /* Handle CSI RM. */
1699413e5e52Snicm static void
170070988a14Snicm input_csi_dispatch_rm(struct input_ctx *ictx)
170170988a14Snicm {
17023248c880Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
170370988a14Snicm 	u_int			 i;
170470988a14Snicm 
170570988a14Snicm 	for (i = 0; i < ictx->param_list_len; i++) {
170670988a14Snicm 		switch (input_get(ictx, i, 0, -1)) {
1707902fbd84Snicm 		case -1:
1708902fbd84Snicm 			break;
1709311827fbSnicm 		case 4:		/* IRM */
17103248c880Snicm 			screen_write_mode_clear(sctx, MODE_INSERT);
1711311827fbSnicm 			break;
171204836468Snicm 		case 34:
171349b698acSnicm 			screen_write_mode_set(sctx, MODE_CURSOR_VERY_VISIBLE);
171404836468Snicm 			break;
1715311827fbSnicm 		default:
1716dee808c1Snicm 			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1717311827fbSnicm 			break;
1718311827fbSnicm 		}
171970988a14Snicm 	}
172070988a14Snicm }
172170988a14Snicm 
172270988a14Snicm /* Handle CSI private RM. */
1723413e5e52Snicm static void
172470988a14Snicm input_csi_dispatch_rm_private(struct input_ctx *ictx)
172570988a14Snicm {
17263248c880Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
172729ebed37Snicm 	struct grid_cell	*gc = &ictx->cell.cell;
172870988a14Snicm 	u_int			 i;
172970988a14Snicm 
173070988a14Snicm 	for (i = 0; i < ictx->param_list_len; i++) {
173170988a14Snicm 		switch (input_get(ictx, i, 0, -1)) {
1732902fbd84Snicm 		case -1:
1733902fbd84Snicm 			break;
173470988a14Snicm 		case 1:		/* DECCKM */
17353248c880Snicm 			screen_write_mode_clear(sctx, MODE_KCURSOR);
1736311827fbSnicm 			break;
1737d30da15dSnicm 		case 3:		/* DECCOLM */
17385c6c7001Snicm 			screen_write_cursormove(sctx, 0, 0, 1);
173929ebed37Snicm 			screen_write_clearscreen(sctx, gc->bg);
1740d30da15dSnicm 			break;
1741ad47aa1bSnicm 		case 6:		/* DECOM */
17423248c880Snicm 			screen_write_mode_clear(sctx, MODE_ORIGIN);
17435c6c7001Snicm 			screen_write_cursormove(sctx, 0, 0, 1);
1744ad47aa1bSnicm 			break;
174584c47e4aSnicm 		case 7:		/* DECAWM */
17463248c880Snicm 			screen_write_mode_clear(sctx, MODE_WRAP);
174784c47e4aSnicm 			break;
174804836468Snicm 		case 12:
174949b698acSnicm 			screen_write_mode_clear(sctx, MODE_CURSOR_BLINKING);
17506a238659Snicm 			screen_write_mode_set(sctx, MODE_CURSOR_BLINKING_SET);
175104836468Snicm 			break;
1752311827fbSnicm 		case 25:	/* TCEM */
17533248c880Snicm 			screen_write_mode_clear(sctx, MODE_CURSOR);
1754311827fbSnicm 			break;
1755311827fbSnicm 		case 1000:
175606598938Snicm 		case 1001:
175706598938Snicm 		case 1002:
17589f26c5b1Snicm 		case 1003:
17593248c880Snicm 			screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
1760311827fbSnicm 			break;
176102ae1365Snicm 		case 1004:
17623248c880Snicm 			screen_write_mode_clear(sctx, MODE_FOCUSON);
176302ae1365Snicm 			break;
17643b213501Snicm 		case 1005:
17653248c880Snicm 			screen_write_mode_clear(sctx, MODE_MOUSE_UTF8);
17663b213501Snicm 			break;
17676c0777c5Snicm 		case 1006:
17683248c880Snicm 			screen_write_mode_clear(sctx, MODE_MOUSE_SGR);
17696c0777c5Snicm 			break;
1770544e828aSnicm 		case 47:
1771544e828aSnicm 		case 1047:
177283e83a91Snicm 			screen_write_alternateoff(sctx, gc, 0);
1773544e828aSnicm 			break;
1774953d773cSnicm 		case 1049:
177583e83a91Snicm 			screen_write_alternateoff(sctx, gc, 1);
1776953d773cSnicm 			break;
17777e9c16f9Snicm 		case 2004:
17783248c880Snicm 			screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
17797e9c16f9Snicm 			break;
1780311827fbSnicm 		default:
1781dee808c1Snicm 			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1782311827fbSnicm 			break;
1783311827fbSnicm 		}
178470988a14Snicm 	}
178570988a14Snicm }
178670988a14Snicm 
178770988a14Snicm /* Handle CSI SM. */
1788413e5e52Snicm static void
178970988a14Snicm input_csi_dispatch_sm(struct input_ctx *ictx)
179070988a14Snicm {
17913248c880Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
179270988a14Snicm 	u_int			 i;
179370988a14Snicm 
179470988a14Snicm 	for (i = 0; i < ictx->param_list_len; i++) {
179570988a14Snicm 		switch (input_get(ictx, i, 0, -1)) {
1796902fbd84Snicm 		case -1:
1797902fbd84Snicm 			break;
1798311827fbSnicm 		case 4:		/* IRM */
17993248c880Snicm 			screen_write_mode_set(sctx, MODE_INSERT);
1800311827fbSnicm 			break;
180104836468Snicm 		case 34:
180249b698acSnicm 			screen_write_mode_clear(sctx, MODE_CURSOR_VERY_VISIBLE);
180304836468Snicm 			break;
1804311827fbSnicm 		default:
1805dee808c1Snicm 			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1806311827fbSnicm 			break;
1807311827fbSnicm 		}
180870988a14Snicm 	}
180970988a14Snicm }
181070988a14Snicm 
181170988a14Snicm /* Handle CSI private SM. */
1812413e5e52Snicm static void
181370988a14Snicm input_csi_dispatch_sm_private(struct input_ctx *ictx)
181470988a14Snicm {
18153248c880Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
181629ebed37Snicm 	struct grid_cell	*gc = &ictx->cell.cell;
181770988a14Snicm 	u_int			 i;
181870988a14Snicm 
181970988a14Snicm 	for (i = 0; i < ictx->param_list_len; i++) {
182070988a14Snicm 		switch (input_get(ictx, i, 0, -1)) {
1821902fbd84Snicm 		case -1:
1822902fbd84Snicm 			break;
182370988a14Snicm 		case 1:		/* DECCKM */
18243248c880Snicm 			screen_write_mode_set(sctx, MODE_KCURSOR);
1825dee808c1Snicm 			break;
1826dee808c1Snicm 		case 3:		/* DECCOLM */
18275c6c7001Snicm 			screen_write_cursormove(sctx, 0, 0, 1);
18283248c880Snicm 			screen_write_clearscreen(sctx, ictx->cell.cell.bg);
1829dee808c1Snicm 			break;
1830ad47aa1bSnicm 		case 6:		/* DECOM */
18313248c880Snicm 			screen_write_mode_set(sctx, MODE_ORIGIN);
18325c6c7001Snicm 			screen_write_cursormove(sctx, 0, 0, 1);
1833ad47aa1bSnicm 			break;
183484c47e4aSnicm 		case 7:		/* DECAWM */
18353248c880Snicm 			screen_write_mode_set(sctx, MODE_WRAP);
183684c47e4aSnicm 			break;
183704836468Snicm 		case 12:
183849b698acSnicm 			screen_write_mode_set(sctx, MODE_CURSOR_BLINKING);
18396a238659Snicm 			screen_write_mode_set(sctx, MODE_CURSOR_BLINKING_SET);
184004836468Snicm 			break;
1841dee808c1Snicm 		case 25:	/* TCEM */
18423248c880Snicm 			screen_write_mode_set(sctx, MODE_CURSOR);
1843dee808c1Snicm 			break;
1844dee808c1Snicm 		case 1000:
18453248c880Snicm 			screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
18463248c880Snicm 			screen_write_mode_set(sctx, MODE_MOUSE_STANDARD);
184706598938Snicm 			break;
184806598938Snicm 		case 1002:
18493248c880Snicm 			screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
18503248c880Snicm 			screen_write_mode_set(sctx, MODE_MOUSE_BUTTON);
185106598938Snicm 			break;
18529f26c5b1Snicm 		case 1003:
18533248c880Snicm 			screen_write_mode_clear(sctx, ALL_MOUSE_MODES);
18543248c880Snicm 			screen_write_mode_set(sctx, MODE_MOUSE_ALL);
18559f26c5b1Snicm 			break;
185602ae1365Snicm 		case 1004:
18573248c880Snicm 			screen_write_mode_set(sctx, MODE_FOCUSON);
185802ae1365Snicm 			break;
18593b213501Snicm 		case 1005:
18603248c880Snicm 			screen_write_mode_set(sctx, MODE_MOUSE_UTF8);
18613b213501Snicm 			break;
18626c0777c5Snicm 		case 1006:
18633248c880Snicm 			screen_write_mode_set(sctx, MODE_MOUSE_SGR);
18646c0777c5Snicm 			break;
1865544e828aSnicm 		case 47:
1866544e828aSnicm 		case 1047:
186783e83a91Snicm 			screen_write_alternateon(sctx, gc, 0);
1868544e828aSnicm 			break;
1869dee808c1Snicm 		case 1049:
187083e83a91Snicm 			screen_write_alternateon(sctx, gc, 1);
1871dee808c1Snicm 			break;
18727e9c16f9Snicm 		case 2004:
18733248c880Snicm 			screen_write_mode_set(sctx, MODE_BRACKETPASTE);
18747e9c16f9Snicm 			break;
1875dee808c1Snicm 		default:
1876dee808c1Snicm 			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1877311827fbSnicm 			break;
1878311827fbSnicm 		}
1879311827fbSnicm 	}
1880dee808c1Snicm }
1881dee808c1Snicm 
18827b23d14cSnicm /* Handle CSI graphics SM. */
18837b23d14cSnicm static void
188404d313c5Snicm input_csi_dispatch_sm_graphics(__unused struct input_ctx *ictx)
18857b23d14cSnicm {
18867b23d14cSnicm }
18877b23d14cSnicm 
1888c8af5297Snicm /* Handle CSI window operations. */
1889413e5e52Snicm static void
1890c8af5297Snicm input_csi_dispatch_winops(struct input_ctx *ictx)
1891c8af5297Snicm {
18923248c880Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
1893cf6b0e8fSnicm 	struct screen		*s = sctx->s;
1894c8af5297Snicm 	struct window_pane	*wp = ictx->wp;
1895ce01693aSnicm 	struct window		*w = NULL;
1896cf6b0e8fSnicm 	u_int			 x = screen_size_x(s), y = screen_size_y(s);
1897c8af5297Snicm 	int			 n, m;
1898c8af5297Snicm 
1899ce01693aSnicm 	if (wp != NULL)
1900ce01693aSnicm 		w = wp->window;
1901ce01693aSnicm 
1902c8af5297Snicm 	m = 0;
1903c8af5297Snicm 	while ((n = input_get(ictx, m, 0, -1)) != -1) {
1904c8af5297Snicm 		switch (n) {
1905c8af5297Snicm 		case 1:
1906c8af5297Snicm 		case 2:
1907c8af5297Snicm 		case 5:
1908c8af5297Snicm 		case 6:
1909c8af5297Snicm 		case 7:
1910c8af5297Snicm 		case 11:
1911c8af5297Snicm 		case 13:
1912c8af5297Snicm 		case 20:
1913c8af5297Snicm 		case 21:
1914c8af5297Snicm 		case 24:
1915c8af5297Snicm 			break;
1916c8af5297Snicm 		case 3:
1917c8af5297Snicm 		case 4:
1918c8af5297Snicm 		case 8:
1919c8af5297Snicm 			m++;
1920c8af5297Snicm 			if (input_get(ictx, m, 0, -1) == -1)
1921c8af5297Snicm 				return;
1922c8af5297Snicm 			/* FALLTHROUGH */
1923c8af5297Snicm 		case 9:
1924c8af5297Snicm 		case 10:
1925c8af5297Snicm 			m++;
1926c8af5297Snicm 			if (input_get(ictx, m, 0, -1) == -1)
1927c8af5297Snicm 				return;
1928c8af5297Snicm 			break;
19297b23d14cSnicm 		case 14:
1930ce01693aSnicm 			if (w == NULL)
1931ce01693aSnicm 				break;
1932ce01693aSnicm 			input_reply(ictx, "\033[4;%u;%ut", y * w->ypixel,
1933ce01693aSnicm 			    x * w->xpixel);
19347b23d14cSnicm 			break;
19357b23d14cSnicm 		case 15:
1936ce01693aSnicm 			if (w == NULL)
1937ce01693aSnicm 				break;
1938ce01693aSnicm 			input_reply(ictx, "\033[5;%u;%ut", y * w->ypixel,
1939ce01693aSnicm 			    x * w->xpixel);
19407b23d14cSnicm 			break;
19417b23d14cSnicm 		case 16:
1942ce01693aSnicm 			if (w == NULL)
1943ce01693aSnicm 				break;
1944ce01693aSnicm 			input_reply(ictx, "\033[6;%u;%ut", w->ypixel,
1945ce01693aSnicm 			    w->xpixel);
19467b23d14cSnicm 			break;
19477b23d14cSnicm 		case 18:
19487b23d14cSnicm 			input_reply(ictx, "\033[8;%u;%ut", y, x);
19497b23d14cSnicm 			break;
19507b23d14cSnicm 		case 19:
19517b23d14cSnicm 			input_reply(ictx, "\033[9;%u;%ut", y, x);
19527b23d14cSnicm 			break;
19532981c1f2Snicm 		case 22:
19542981c1f2Snicm 			m++;
19552981c1f2Snicm 			switch (input_get(ictx, m, 0, -1)) {
19562981c1f2Snicm 			case -1:
19572981c1f2Snicm 				return;
19582981c1f2Snicm 			case 0:
19592981c1f2Snicm 			case 2:
19603248c880Snicm 				screen_push_title(sctx->s);
19612981c1f2Snicm 				break;
19622981c1f2Snicm 			}
19632981c1f2Snicm 			break;
19642981c1f2Snicm 		case 23:
19652981c1f2Snicm 			m++;
19662981c1f2Snicm 			switch (input_get(ictx, m, 0, -1)) {
19672981c1f2Snicm 			case -1:
19682981c1f2Snicm 				return;
19692981c1f2Snicm 			case 0:
19702981c1f2Snicm 			case 2:
19713248c880Snicm 				screen_pop_title(sctx->s);
197233a1e283Snicm 				if (wp == NULL)
197333a1e283Snicm 					break;
1974073a2214Snicm 				notify_pane("pane-title-changed", wp);
1975ce01693aSnicm 				server_redraw_window_borders(w);
1976ce01693aSnicm 				server_status_window(w);
19772981c1f2Snicm 				break;
19782981c1f2Snicm 			}
19792981c1f2Snicm 			break;
1980c8af5297Snicm 		default:
1981c8af5297Snicm 			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1982c8af5297Snicm 			break;
1983c8af5297Snicm 		}
1984c8af5297Snicm 		m++;
1985c8af5297Snicm 	}
1986c8af5297Snicm }
1987c8af5297Snicm 
1988902fbd84Snicm /* Helper for 256 colour SGR. */
1989902fbd84Snicm static int
1990902fbd84Snicm input_csi_dispatch_sgr_256_do(struct input_ctx *ictx, int fgbg, int c)
1991efb8394dSnicm {
1992efb8394dSnicm 	struct grid_cell	*gc = &ictx->cell.cell;
1993efb8394dSnicm 
1994902fbd84Snicm 	if (c == -1 || c > 255) {
199592c661c5Snicm 		if (fgbg == 38)
1996efb8394dSnicm 			gc->fg = 8;
199792c661c5Snicm 		else if (fgbg == 48)
1998efb8394dSnicm 			gc->bg = 8;
1999efb8394dSnicm 	} else {
200092c661c5Snicm 		if (fgbg == 38)
200192c661c5Snicm 			gc->fg = c | COLOUR_FLAG_256;
200292c661c5Snicm 		else if (fgbg == 48)
200392c661c5Snicm 			gc->bg = c | COLOUR_FLAG_256;
2004bc174b93Snicm 		else if (fgbg == 58)
2005bc174b93Snicm 			gc->us = c | COLOUR_FLAG_256;
2006efb8394dSnicm 	}
2007902fbd84Snicm 	return (1);
2008902fbd84Snicm }
2009902fbd84Snicm 
2010902fbd84Snicm /* Handle CSI SGR for 256 colours. */
2011902fbd84Snicm static void
2012902fbd84Snicm input_csi_dispatch_sgr_256(struct input_ctx *ictx, int fgbg, u_int *i)
2013902fbd84Snicm {
2014902fbd84Snicm 	int	c;
2015902fbd84Snicm 
2016902fbd84Snicm 	c = input_get(ictx, (*i) + 1, 0, -1);
2017902fbd84Snicm 	if (input_csi_dispatch_sgr_256_do(ictx, fgbg, c))
2018902fbd84Snicm 		(*i)++;
2019902fbd84Snicm }
2020902fbd84Snicm 
2021902fbd84Snicm /* Helper for RGB colour SGR. */
2022902fbd84Snicm static int
2023902fbd84Snicm input_csi_dispatch_sgr_rgb_do(struct input_ctx *ictx, int fgbg, int r, int g,
2024902fbd84Snicm     int b)
2025902fbd84Snicm {
2026902fbd84Snicm 	struct grid_cell	*gc = &ictx->cell.cell;
2027902fbd84Snicm 
2028902fbd84Snicm 	if (r == -1 || r > 255)
2029902fbd84Snicm 		return (0);
2030902fbd84Snicm 	if (g == -1 || g > 255)
2031902fbd84Snicm 		return (0);
2032902fbd84Snicm 	if (b == -1 || b > 255)
2033902fbd84Snicm 		return (0);
2034902fbd84Snicm 
2035902fbd84Snicm 	if (fgbg == 38)
2036902fbd84Snicm 		gc->fg = colour_join_rgb(r, g, b);
2037902fbd84Snicm 	else if (fgbg == 48)
2038902fbd84Snicm 		gc->bg = colour_join_rgb(r, g, b);
2039bc174b93Snicm 	else if (fgbg == 58)
2040bc174b93Snicm 		gc->us = colour_join_rgb(r, g, b);
2041902fbd84Snicm 	return (1);
2042efb8394dSnicm }
2043efb8394dSnicm 
2044efb8394dSnicm /* Handle CSI SGR for RGB colours. */
2045413e5e52Snicm static void
2046efb8394dSnicm input_csi_dispatch_sgr_rgb(struct input_ctx *ictx, int fgbg, u_int *i)
2047efb8394dSnicm {
2048a4f3e970Snicm 	int	r, g, b;
2049efb8394dSnicm 
2050902fbd84Snicm 	r = input_get(ictx, (*i) + 1, 0, -1);
2051902fbd84Snicm 	g = input_get(ictx, (*i) + 2, 0, -1);
2052902fbd84Snicm 	b = input_get(ictx, (*i) + 3, 0, -1);
2053902fbd84Snicm 	if (input_csi_dispatch_sgr_rgb_do(ictx, fgbg, r, g, b))
2054902fbd84Snicm 		(*i) += 3;
2055902fbd84Snicm }
2056efb8394dSnicm 
2057902fbd84Snicm /* Handle CSI SGR with a ISO parameter. */
2058902fbd84Snicm static void
2059902fbd84Snicm input_csi_dispatch_sgr_colon(struct input_ctx *ictx, u_int i)
2060902fbd84Snicm {
206142caa339Snicm 	struct grid_cell	*gc = &ictx->cell.cell;
2062902fbd84Snicm 	char			*s = ictx->param_list[i].str, *copy, *ptr, *out;
2063902fbd84Snicm 	int			 p[8];
2064902fbd84Snicm 	u_int			 n;
2065902fbd84Snicm 	const char		*errstr;
2066902fbd84Snicm 
2067902fbd84Snicm 	for (n = 0; n < nitems(p); n++)
2068902fbd84Snicm 		p[n] = -1;
2069902fbd84Snicm 	n = 0;
2070902fbd84Snicm 
2071902fbd84Snicm 	ptr = copy = xstrdup(s);
2072902fbd84Snicm 	while ((out = strsep(&ptr, ":")) != NULL) {
2073b154cc79Snicm 		if (*out != '\0') {
2074902fbd84Snicm 			p[n++] = strtonum(out, 0, INT_MAX, &errstr);
2075902fbd84Snicm 			if (errstr != NULL || n == nitems(p)) {
2076902fbd84Snicm 				free(copy);
2077902fbd84Snicm 				return;
2078902fbd84Snicm 			}
20798b213474Snicm 		} else {
20808a8caf69Snicm 			n++;
20818b213474Snicm 			if (n == nitems(p)) {
20828b213474Snicm 				free(copy);
20838b213474Snicm 				return;
20848b213474Snicm 			}
20858b213474Snicm 		}
2086902fbd84Snicm 		log_debug("%s: %u = %d", __func__, n - 1, p[n - 1]);
2087902fbd84Snicm 	}
2088902fbd84Snicm 	free(copy);
2089902fbd84Snicm 
209042caa339Snicm 	if (n == 0)
209142caa339Snicm 		return;
209242caa339Snicm 	if (p[0] == 4) {
209342caa339Snicm 		if (n != 2)
209442caa339Snicm 			return;
209542caa339Snicm 		switch (p[1]) {
209642caa339Snicm 		case 0:
209742caa339Snicm 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
209842caa339Snicm 			break;
209942caa339Snicm 		case 1:
210042caa339Snicm 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
210142caa339Snicm 			gc->attr |= GRID_ATTR_UNDERSCORE;
210242caa339Snicm 			break;
210342caa339Snicm 		case 2:
210442caa339Snicm 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
210542caa339Snicm 			gc->attr |= GRID_ATTR_UNDERSCORE_2;
210642caa339Snicm 			break;
210742caa339Snicm 		case 3:
210842caa339Snicm 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
210942caa339Snicm 			gc->attr |= GRID_ATTR_UNDERSCORE_3;
211042caa339Snicm 			break;
211142caa339Snicm 		case 4:
211242caa339Snicm 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
211342caa339Snicm 			gc->attr |= GRID_ATTR_UNDERSCORE_4;
211442caa339Snicm 			break;
211542caa339Snicm 		case 5:
211642caa339Snicm 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
211742caa339Snicm 			gc->attr |= GRID_ATTR_UNDERSCORE_5;
211842caa339Snicm 			break;
211942caa339Snicm 		}
212042caa339Snicm 		return;
212142caa339Snicm 	}
2122bc174b93Snicm 	if (n < 2 || (p[0] != 38 && p[0] != 48 && p[0] != 58))
2123902fbd84Snicm 		return;
21247cb3d29bSnicm 	switch (p[1]) {
21257cb3d29bSnicm 	case 2:
21267cb3d29bSnicm 		if (n < 3)
21277cb3d29bSnicm 			break;
21287cb3d29bSnicm 		if (n == 5)
2129b154cc79Snicm 			i = 2;
2130b154cc79Snicm 		else
21317cb3d29bSnicm 			i = 3;
21327cb3d29bSnicm 		if (n < i + 3)
2133902fbd84Snicm 			break;
21347cb3d29bSnicm 		input_csi_dispatch_sgr_rgb_do(ictx, p[0], p[i], p[i + 1],
21357cb3d29bSnicm 		    p[i + 2]);
2136902fbd84Snicm 		break;
2137902fbd84Snicm 	case 5:
21387cb3d29bSnicm 		if (n < 3)
2139902fbd84Snicm 			break;
21407cb3d29bSnicm 		input_csi_dispatch_sgr_256_do(ictx, p[0], p[2]);
2141902fbd84Snicm 		break;
2142902fbd84Snicm 	}
2143efb8394dSnicm }
2144efb8394dSnicm 
2145dee808c1Snicm /* Handle CSI SGR. */
2146413e5e52Snicm static void
2147dee808c1Snicm input_csi_dispatch_sgr(struct input_ctx *ictx)
2148311827fbSnicm {
2149c2a06f72Snicm 	struct grid_cell	*gc = &ictx->cell.cell;
2150c3035900Snicm 	u_int			 i, link;
2151efb8394dSnicm 	int			 n;
2152311827fbSnicm 
2153dee808c1Snicm 	if (ictx->param_list_len == 0) {
2154311827fbSnicm 		memcpy(gc, &grid_default_cell, sizeof *gc);
2155311827fbSnicm 		return;
2156311827fbSnicm 	}
2157311827fbSnicm 
2158dee808c1Snicm 	for (i = 0; i < ictx->param_list_len; i++) {
2159902fbd84Snicm 		if (ictx->param_list[i].type == INPUT_STRING) {
2160902fbd84Snicm 			input_csi_dispatch_sgr_colon(ictx, i);
2161902fbd84Snicm 			continue;
2162902fbd84Snicm 		}
2163dee808c1Snicm 		n = input_get(ictx, i, 0, 0);
2164902fbd84Snicm 		if (n == -1)
2165902fbd84Snicm 			continue;
2166311827fbSnicm 
2167bc174b93Snicm 		if (n == 38 || n == 48 || n == 58) {
2168311827fbSnicm 			i++;
2169efb8394dSnicm 			switch (input_get(ictx, i, 0, -1)) {
2170efb8394dSnicm 			case 2:
2171efb8394dSnicm 				input_csi_dispatch_sgr_rgb(ictx, n, &i);
2172efb8394dSnicm 				break;
2173efb8394dSnicm 			case 5:
2174efb8394dSnicm 				input_csi_dispatch_sgr_256(ictx, n, &i);
2175efb8394dSnicm 				break;
2176311827fbSnicm 			}
2177311827fbSnicm 			continue;
2178311827fbSnicm 		}
2179311827fbSnicm 
2180dee808c1Snicm 		switch (n) {
2181311827fbSnicm 		case 0:
2182c3035900Snicm 			link = gc->link;
2183311827fbSnicm 			memcpy(gc, &grid_default_cell, sizeof *gc);
2184c3035900Snicm 			gc->link = link;
2185311827fbSnicm 			break;
2186311827fbSnicm 		case 1:
2187311827fbSnicm 			gc->attr |= GRID_ATTR_BRIGHT;
2188311827fbSnicm 			break;
2189311827fbSnicm 		case 2:
2190311827fbSnicm 			gc->attr |= GRID_ATTR_DIM;
2191311827fbSnicm 			break;
2192311827fbSnicm 		case 3:
2193311827fbSnicm 			gc->attr |= GRID_ATTR_ITALICS;
2194311827fbSnicm 			break;
2195311827fbSnicm 		case 4:
219642caa339Snicm 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2197311827fbSnicm 			gc->attr |= GRID_ATTR_UNDERSCORE;
2198311827fbSnicm 			break;
2199311827fbSnicm 		case 5:
22005ff7e4feSnicm 		case 6:
2201311827fbSnicm 			gc->attr |= GRID_ATTR_BLINK;
2202311827fbSnicm 			break;
2203311827fbSnicm 		case 7:
2204311827fbSnicm 			gc->attr |= GRID_ATTR_REVERSE;
2205311827fbSnicm 			break;
2206311827fbSnicm 		case 8:
2207311827fbSnicm 			gc->attr |= GRID_ATTR_HIDDEN;
2208311827fbSnicm 			break;
22091779e050Snicm 		case 9:
22101779e050Snicm 			gc->attr |= GRID_ATTR_STRIKETHROUGH;
22111779e050Snicm 			break;
22125ff7e4feSnicm 		case 21:
22135ff7e4feSnicm 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
22145ff7e4feSnicm 			gc->attr |= GRID_ATTR_UNDERSCORE_2;
22155ff7e4feSnicm 			break;
2216311827fbSnicm 		case 22:
2217311827fbSnicm 			gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
2218311827fbSnicm 			break;
2219311827fbSnicm 		case 23:
2220311827fbSnicm 			gc->attr &= ~GRID_ATTR_ITALICS;
2221311827fbSnicm 			break;
2222311827fbSnicm 		case 24:
222342caa339Snicm 			gc->attr &= ~GRID_ATTR_ALL_UNDERSCORE;
2224311827fbSnicm 			break;
2225311827fbSnicm 		case 25:
2226311827fbSnicm 			gc->attr &= ~GRID_ATTR_BLINK;
2227311827fbSnicm 			break;
2228311827fbSnicm 		case 27:
2229311827fbSnicm 			gc->attr &= ~GRID_ATTR_REVERSE;
2230311827fbSnicm 			break;
2231a67d9d12Snicm 		case 28:
2232a67d9d12Snicm 			gc->attr &= ~GRID_ATTR_HIDDEN;
2233a67d9d12Snicm 			break;
22341779e050Snicm 		case 29:
22351779e050Snicm 			gc->attr &= ~GRID_ATTR_STRIKETHROUGH;
22361779e050Snicm 			break;
2237311827fbSnicm 		case 30:
2238311827fbSnicm 		case 31:
2239311827fbSnicm 		case 32:
2240311827fbSnicm 		case 33:
2241311827fbSnicm 		case 34:
2242311827fbSnicm 		case 35:
2243311827fbSnicm 		case 36:
2244311827fbSnicm 		case 37:
2245dee808c1Snicm 			gc->fg = n - 30;
2246311827fbSnicm 			break;
2247311827fbSnicm 		case 39:
2248311827fbSnicm 			gc->fg = 8;
2249311827fbSnicm 			break;
2250311827fbSnicm 		case 40:
2251311827fbSnicm 		case 41:
2252311827fbSnicm 		case 42:
2253311827fbSnicm 		case 43:
2254311827fbSnicm 		case 44:
2255311827fbSnicm 		case 45:
2256311827fbSnicm 		case 46:
2257311827fbSnicm 		case 47:
2258dee808c1Snicm 			gc->bg = n - 40;
2259311827fbSnicm 			break;
2260311827fbSnicm 		case 49:
2261311827fbSnicm 			gc->bg = 8;
2262311827fbSnicm 			break;
2263d37269efSnicm 		case 53:
2264d37269efSnicm 			gc->attr |= GRID_ATTR_OVERLINE;
2265d37269efSnicm 			break;
2266d37269efSnicm 		case 55:
2267d37269efSnicm 			gc->attr &= ~GRID_ATTR_OVERLINE;
2268d37269efSnicm 			break;
2269bc174b93Snicm 		case 59:
2270f353bcb0Snicm 			gc->us = 8;
2271bc174b93Snicm 			break;
2272316e7437Snicm 		case 90:
2273316e7437Snicm 		case 91:
2274316e7437Snicm 		case 92:
2275316e7437Snicm 		case 93:
2276316e7437Snicm 		case 94:
2277316e7437Snicm 		case 95:
2278316e7437Snicm 		case 96:
2279316e7437Snicm 		case 97:
2280dee808c1Snicm 			gc->fg = n;
2281316e7437Snicm 			break;
2282316e7437Snicm 		case 100:
2283316e7437Snicm 		case 101:
2284316e7437Snicm 		case 102:
2285316e7437Snicm 		case 103:
2286316e7437Snicm 		case 104:
2287316e7437Snicm 		case 105:
2288316e7437Snicm 		case 106:
2289316e7437Snicm 		case 107:
2290869852caSnicm 			gc->bg = n - 10;
2291316e7437Snicm 			break;
2292311827fbSnicm 		}
2293311827fbSnicm 	}
2294311827fbSnicm }
2295dee808c1Snicm 
229690866723Snicm /* End of input with BEL. */
229790866723Snicm static int
229890866723Snicm input_end_bel(struct input_ctx *ictx)
229990866723Snicm {
230090866723Snicm 	log_debug("%s", __func__);
230190866723Snicm 
230290866723Snicm 	ictx->input_end = INPUT_END_BEL;
230390866723Snicm 
230490866723Snicm 	return (0);
230590866723Snicm }
230690866723Snicm 
23075842cea5Snicm /* DCS string started. */
23085842cea5Snicm static void
23095842cea5Snicm input_enter_dcs(struct input_ctx *ictx)
23105842cea5Snicm {
23115842cea5Snicm 	log_debug("%s", __func__);
23125842cea5Snicm 
23135842cea5Snicm 	input_clear(ictx);
23145842cea5Snicm 	input_start_timer(ictx);
231580c8bfd3Snicm 	ictx->flags &= ~INPUT_LAST;
23165842cea5Snicm }
23175842cea5Snicm 
2318885f7078Snicm /* DCS terminator (ST) received. */
2319413e5e52Snicm static int
2320885f7078Snicm input_dcs_dispatch(struct input_ctx *ictx)
2321dee808c1Snicm {
23225e0eec07Snicm 	struct window_pane	*wp = ictx->wp;
23233248c880Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
23243248c880Snicm 	u_char			*buf = ictx->input_buf;
23253248c880Snicm 	size_t			 len = ictx->input_len;
2326885f7078Snicm 	const char		 prefix[] = "tmux;";
23273248c880Snicm 	const u_int		 prefixlen = (sizeof prefix) - 1;
2328930d157dSnicm 	long long		 allow_passthrough = 0;
2329dee808c1Snicm 
23305e0eec07Snicm 	if (wp == NULL)
23315e0eec07Snicm 		return (0);
2332eb1b93f9Snicm 	if (ictx->flags & INPUT_DISCARD) {
2333eb1b93f9Snicm 		log_debug("%s: %zu bytes (discard)", __func__, len);
2334885f7078Snicm 		return (0);
2335eb1b93f9Snicm 	}
2336eb1b93f9Snicm 	log_debug("%s: %zu bytes", __func__, len);
2337eb1b93f9Snicm 
2338eb1b93f9Snicm 	allow_passthrough = options_get_number(wp->options, "allow-passthrough");
2339930d157dSnicm 	if (!allow_passthrough)
23405e0eec07Snicm 		return (0);
23413248c880Snicm 	log_debug("%s: \"%s\"", __func__, buf);
2342885f7078Snicm 
2343930d157dSnicm 	if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0) {
2344930d157dSnicm 		screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen,
2345930d157dSnicm 		    allow_passthrough == 2);
2346930d157dSnicm 	}
2347dee808c1Snicm 
2348885f7078Snicm 	return (0);
2349dee808c1Snicm }
2350dee808c1Snicm 
2351dee808c1Snicm /* OSC string started. */
2352413e5e52Snicm static void
2353dee808c1Snicm input_enter_osc(struct input_ctx *ictx)
2354dee808c1Snicm {
2355dee808c1Snicm 	log_debug("%s", __func__);
2356dee808c1Snicm 
23574e829c14Snicm 	input_clear(ictx);
23585842cea5Snicm 	input_start_timer(ictx);
235980c8bfd3Snicm 	ictx->flags &= ~INPUT_LAST;
2360dee808c1Snicm }
2361dee808c1Snicm 
2362dee808c1Snicm /* OSC terminator (ST) received. */
2363413e5e52Snicm static void
2364dee808c1Snicm input_exit_osc(struct input_ctx *ictx)
2365dee808c1Snicm {
23663248c880Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
236729ebed37Snicm 	struct window_pane	*wp = ictx->wp;
2368e417d1c0Snicm 	u_char			*p = ictx->input_buf;
2369e5f4d2afSnicm 	u_int			 option;
2370e417d1c0Snicm 
2371dee808c1Snicm 	if (ictx->flags & INPUT_DISCARD)
2372dee808c1Snicm 		return;
2373e417d1c0Snicm 	if (ictx->input_len < 1 || *p < '0' || *p > '9')
2374dee808c1Snicm 		return;
2375dee808c1Snicm 
237690866723Snicm 	log_debug("%s: \"%s\" (end %s)", __func__, p,
237790866723Snicm 	    ictx->input_end == INPUT_END_ST ? "ST" : "BEL");
2378e417d1c0Snicm 
2379e417d1c0Snicm 	option = 0;
2380e417d1c0Snicm 	while (*p >= '0' && *p <= '9')
2381e417d1c0Snicm 		option = option * 10 + *p++ - '0';
2382fdbaf1ceSnicm 	if (*p != ';' && *p != '\0')
2383fdbaf1ceSnicm 		return;
2384e417d1c0Snicm 	if (*p == ';')
2385e417d1c0Snicm 		p++;
2386e417d1c0Snicm 
2387e417d1c0Snicm 	switch (option) {
2388e417d1c0Snicm 	case 0:
2389e417d1c0Snicm 	case 2:
23908db6b63cSnicm 		if (wp != NULL &&
23918db6b63cSnicm 		    options_get_number(wp->options, "allow-set-title") &&
23928db6b63cSnicm 		    screen_set_title(sctx->s, p)) {
2393073a2214Snicm 			notify_pane("pane-title-changed", wp);
239401c0c428Snicm 			server_redraw_window_borders(wp->window);
239501c0c428Snicm 			server_status_window(wp->window);
239601c0c428Snicm 		}
2397e417d1c0Snicm 		break;
2398e16c1698Snicm 	case 4:
239990866723Snicm 		input_osc_4(ictx, p);
2400e16c1698Snicm 		break;
2401e9afa876Snicm 	case 7:
2402e9afa876Snicm 		if (utf8_isvalid(p)) {
2403e9afa876Snicm 			screen_set_path(sctx->s, p);
240401c0c428Snicm 			if (wp != NULL) {
240501c0c428Snicm 				server_redraw_window_borders(wp->window);
240629ebed37Snicm 				server_status_window(wp->window);
2407e9afa876Snicm 			}
240801c0c428Snicm 		}
2409e9afa876Snicm 		break;
24102df6775cSnicm 	case 8:
24112df6775cSnicm 		input_osc_8(ictx, p);
24122df6775cSnicm 		break;
2413681fc18fSnicm 	case 10:
241490866723Snicm 		input_osc_10(ictx, p);
2415681fc18fSnicm 		break;
2416681fc18fSnicm 	case 11:
241790866723Snicm 		input_osc_11(ictx, p);
2418f7e94a12Snicm 		break;
2419e417d1c0Snicm 	case 12:
24201db1a6bbSnicm 		input_osc_12(ictx, p);
2421e417d1c0Snicm 		break;
2422681fc18fSnicm 	case 52:
242390866723Snicm 		input_osc_52(ictx, p);
2424681fc18fSnicm 		break;
2425e16c1698Snicm 	case 104:
242690866723Snicm 		input_osc_104(ictx, p);
2427e16c1698Snicm 		break;
2428e68ccaeaSnicm 	case 110:
2429e68ccaeaSnicm 		input_osc_110(ictx, p);
2430e68ccaeaSnicm 		break;
2431e68ccaeaSnicm 	case 111:
2432e68ccaeaSnicm 		input_osc_111(ictx, p);
2433e68ccaeaSnicm 		break;
2434e417d1c0Snicm 	case 112:
24351db1a6bbSnicm 		input_osc_112(ictx, p);
2436e417d1c0Snicm 		break;
2437cbbd91a4Snicm 	case 133:
2438cbbd91a4Snicm 		input_osc_133(ictx, p);
2439cbbd91a4Snicm 		break;
2440e417d1c0Snicm 	default:
2441e417d1c0Snicm 		log_debug("%s: unknown '%u'", __func__, option);
2442e417d1c0Snicm 		break;
2443e417d1c0Snicm 	}
2444dee808c1Snicm }
2445dee808c1Snicm 
2446dee808c1Snicm /* APC string started. */
2447413e5e52Snicm static void
2448dee808c1Snicm input_enter_apc(struct input_ctx *ictx)
2449dee808c1Snicm {
2450dee808c1Snicm 	log_debug("%s", __func__);
2451dee808c1Snicm 
24524e829c14Snicm 	input_clear(ictx);
24535842cea5Snicm 	input_start_timer(ictx);
245480c8bfd3Snicm 	ictx->flags &= ~INPUT_LAST;
2455dee808c1Snicm }
2456dee808c1Snicm 
2457dee808c1Snicm /* APC terminator (ST) received. */
2458413e5e52Snicm static void
2459dee808c1Snicm input_exit_apc(struct input_ctx *ictx)
2460dee808c1Snicm {
24613248c880Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
246229ebed37Snicm 	struct window_pane	*wp = ictx->wp;
24633248c880Snicm 
2464dee808c1Snicm 	if (ictx->flags & INPUT_DISCARD)
2465dee808c1Snicm 		return;
2466dee808c1Snicm 	log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2467dee808c1Snicm 
246801c0c428Snicm 	if (screen_set_title(sctx->s, ictx->input_buf) && wp != NULL) {
2469073a2214Snicm 		notify_pane("pane-title-changed", wp);
247001c0c428Snicm 		server_redraw_window_borders(wp->window);
247129ebed37Snicm 		server_status_window(wp->window);
2472dee808c1Snicm 	}
247301c0c428Snicm }
2474dee808c1Snicm 
2475dee808c1Snicm /* Rename string started. */
2476413e5e52Snicm static void
2477dee808c1Snicm input_enter_rename(struct input_ctx *ictx)
2478dee808c1Snicm {
2479dee808c1Snicm 	log_debug("%s", __func__);
2480dee808c1Snicm 
24814e829c14Snicm 	input_clear(ictx);
24825842cea5Snicm 	input_start_timer(ictx);
248380c8bfd3Snicm 	ictx->flags &= ~INPUT_LAST;
2484dee808c1Snicm }
2485dee808c1Snicm 
2486dee808c1Snicm /* Rename terminator (ST) received. */
2487413e5e52Snicm static void
2488dee808c1Snicm input_exit_rename(struct input_ctx *ictx)
2489dee808c1Snicm {
24901f0ae58eSnicm 	struct window_pane	*wp = ictx->wp;
249176a68a20Snicm 	struct window		*w;
249294c0d63cSnicm 	struct options_entry	*o;
24931f0ae58eSnicm 
249429ebed37Snicm 	if (wp == NULL)
249529ebed37Snicm 		return;
2496dee808c1Snicm 	if (ictx->flags & INPUT_DISCARD)
2497dee808c1Snicm 		return;
2498802d7db7Snicm 	if (!options_get_number(ictx->wp->options, "allow-rename"))
24998d7ec369Snicm 		return;
2500dee808c1Snicm 	log_debug("%s: \"%s\"", __func__, ictx->input_buf);
2501dee808c1Snicm 
25029d9ffcabSnicm 	if (!utf8_isvalid(ictx->input_buf))
25039d9ffcabSnicm 		return;
250476a68a20Snicm 	w = wp->window;
25051f0ae58eSnicm 
25061f0ae58eSnicm 	if (ictx->input_len == 0) {
250776a68a20Snicm 		o = options_get_only(w->options, "automatic-rename");
250894c0d63cSnicm 		if (o != NULL)
250994c0d63cSnicm 			options_remove_or_default(o, -1, NULL);
251076a68a20Snicm 		if (!options_get_number(w->options, "automatic-rename"))
251176a68a20Snicm 			window_set_name(w, "");
251276a68a20Snicm 	} else {
251376a68a20Snicm 		options_set_number(w->options, "automatic-rename", 0);
251476a68a20Snicm 		window_set_name(w, ictx->input_buf);
25151f0ae58eSnicm 	}
251676a68a20Snicm 	server_redraw_window_borders(w);
251776a68a20Snicm 	server_status_window(w);
2518dee808c1Snicm }
2519dee808c1Snicm 
2520dee808c1Snicm /* Open UTF-8 character. */
2521413e5e52Snicm static int
2522e51b0e35Snicm input_top_bit_set(struct input_ctx *ictx)
2523dee808c1Snicm {
25243248c880Snicm 	struct screen_write_ctx	*sctx = &ictx->ctx;
252590b6ad54Snicm 	struct utf8_data	*ud = &ictx->utf8data;
2526dee808c1Snicm 
252780c8bfd3Snicm 	ictx->flags &= ~INPUT_LAST;
252890b6ad54Snicm 
2529e51b0e35Snicm 	if (!ictx->utf8started) {
2530e51b0e35Snicm 		if (utf8_open(ud, ictx->ch) != UTF8_MORE)
2531e51b0e35Snicm 			return (0);
2532e51b0e35Snicm 		ictx->utf8started = 1;
2533dee808c1Snicm 		return (0);
2534dee808c1Snicm 	}
2535dee808c1Snicm 
2536e51b0e35Snicm 	switch (utf8_append(ud, ictx->ch)) {
2537e51b0e35Snicm 	case UTF8_MORE:
2538dee808c1Snicm 		return (0);
2539e51b0e35Snicm 	case UTF8_ERROR:
2540e51b0e35Snicm 		ictx->utf8started = 0;
254198da63d5Snicm 		return (0);
2542e51b0e35Snicm 	case UTF8_DONE:
2543e51b0e35Snicm 		break;
254498da63d5Snicm 	}
2545e51b0e35Snicm 	ictx->utf8started = 0;
2546dee808c1Snicm 
254790b6ad54Snicm 	log_debug("%s %hhu '%*s' (width %hhu)", __func__, ud->size,
254890b6ad54Snicm 	    (int)ud->size, ud->data, ud->width);
254990b6ad54Snicm 
255090b6ad54Snicm 	utf8_copy(&ictx->cell.cell.data, ud);
25513248c880Snicm 	screen_write_collect_add(sctx, &ictx->cell.cell);
2552dee808c1Snicm 
255380c8bfd3Snicm 	utf8_copy(&ictx->last, &ictx->cell.cell.data);
255480c8bfd3Snicm 	ictx->flags |= INPUT_LAST;
255580c8bfd3Snicm 
2556dee808c1Snicm 	return (0);
2557dee808c1Snicm }
2558e16c1698Snicm 
25597a3e72b5Snicm /* Reply to a colour request. */
25607a3e72b5Snicm static void
25617a3e72b5Snicm input_osc_colour_reply(struct input_ctx *ictx, u_int n, int c)
25627a3e72b5Snicm {
25637a3e72b5Snicm     u_char	 r, g, b;
25647a3e72b5Snicm     const char	*end;
25657a3e72b5Snicm 
25661db1a6bbSnicm     if (c != -1)
25671db1a6bbSnicm 	    c = colour_force_rgb(c);
25681db1a6bbSnicm     if (c == -1)
25697a3e72b5Snicm 	    return;
25707a3e72b5Snicm     colour_split_rgb(c, &r, &g, &b);
25717a3e72b5Snicm 
25727a3e72b5Snicm     if (ictx->input_end == INPUT_END_BEL)
25737a3e72b5Snicm 	    end = "\007";
25747a3e72b5Snicm     else
25757a3e72b5Snicm 	    end = "\033\\";
2576d3d5e558Snicm     input_reply(ictx, "\033]%u;rgb:%02hhx%02hhx/%02hhx%02hhx/%02hhx%02hhx%s",
2577d3d5e558Snicm 	n, r, r, g, g, b, b, end);
25787a3e72b5Snicm }
25797a3e72b5Snicm 
2580e16c1698Snicm /* Handle the OSC 4 sequence for setting (multiple) palette entries. */
2581e16c1698Snicm static void
258290866723Snicm input_osc_4(struct input_ctx *ictx, const char *p)
2583e16c1698Snicm {
2584e16c1698Snicm 	char	*copy, *s, *next = NULL;
2585e16c1698Snicm 	long	 idx;
258633a1e283Snicm 	int	 c, bad = 0, redraw = 0;
258729ebed37Snicm 
2588e16c1698Snicm 	copy = s = xstrdup(p);
2589e16c1698Snicm 	while (s != NULL && *s != '\0') {
2590e16c1698Snicm 		idx = strtol(s, &next, 10);
259133a1e283Snicm 		if (*next++ != ';') {
259233a1e283Snicm 			bad = 1;
259333a1e283Snicm 			break;
259433a1e283Snicm 		}
259533a1e283Snicm 		if (idx < 0 || idx >= 256) {
259633a1e283Snicm 			bad = 1;
259733a1e283Snicm 			break;
259833a1e283Snicm 		}
2599e16c1698Snicm 
2600e16c1698Snicm 		s = strsep(&next, ";");
260178636d64Snicm 		if (strcmp(s, "?") == 0) {
260278636d64Snicm 			c = colour_palette_get(ictx->palette, idx);
260378636d64Snicm 			if (c != -1)
260478636d64Snicm 				input_osc_colour_reply(ictx, 4, c);
260578636d64Snicm 			continue;
260678636d64Snicm 		}
2607d21788ceSnicm 		if ((c = colour_parseX11(s)) == -1) {
2608e16c1698Snicm 			s = next;
2609e16c1698Snicm 			continue;
2610e16c1698Snicm 		}
261133a1e283Snicm 		if (colour_palette_set(ictx->palette, idx, c))
261233a1e283Snicm 			redraw = 1;
2613e16c1698Snicm 		s = next;
2614e16c1698Snicm 	}
261533a1e283Snicm 	if (bad)
2616e16c1698Snicm 		log_debug("bad OSC 4: %s", p);
261733a1e283Snicm 	if (redraw)
261833a1e283Snicm 		screen_write_fullredraw(&ictx->ctx);
2619e16c1698Snicm 	free(copy);
2620e16c1698Snicm }
2621e16c1698Snicm 
26222df6775cSnicm /* Handle the OSC 8 sequence for embedding hyperlinks. */
26232df6775cSnicm static void
26242df6775cSnicm input_osc_8(struct input_ctx *ictx, const char *p)
26252df6775cSnicm {
26262df6775cSnicm 	struct hyperlinks	*hl = ictx->ctx.s->hyperlinks;
26272df6775cSnicm 	struct grid_cell	*gc = &ictx->cell.cell;
26282df6775cSnicm 	const char		*start, *end, *uri;
26292df6775cSnicm 	char	    		*id = NULL;
26302df6775cSnicm 
26312df6775cSnicm 	for (start = p; (end = strpbrk(start, ":;")) != NULL; start = end + 1) {
26322df6775cSnicm 		if (end - start >= 4 && strncmp(start, "id=", 3) == 0) {
26332df6775cSnicm 			if (id != NULL)
26342df6775cSnicm 				goto bad;
26352df6775cSnicm 			id = xstrndup(start + 3, end - start - 3);
26362df6775cSnicm 		}
26372df6775cSnicm 
26382df6775cSnicm 		/* The first ; is the end of parameters and start of the URI. */
26392df6775cSnicm 		if (*end == ';')
26402df6775cSnicm 			break;
26412df6775cSnicm 	}
26422df6775cSnicm 	if (end == NULL || *end != ';')
26432df6775cSnicm 		goto bad;
26442df6775cSnicm 	uri = end + 1;
26452df6775cSnicm 	if (*uri == '\0') {
26462df6775cSnicm 		gc->link = 0;
26472df6775cSnicm 		free(id);
26482df6775cSnicm 		return;
26492df6775cSnicm 	}
26502df6775cSnicm 	gc->link = hyperlinks_put(hl, uri, id);
26512df6775cSnicm 	if (id == NULL)
26522df6775cSnicm 		log_debug("hyperlink (anonymous) %s = %u", uri, gc->link);
26532df6775cSnicm 	else
26542df6775cSnicm 		log_debug("hyperlink (id=%s) %s = %u", id, uri, gc->link);
26552df6775cSnicm 	free(id);
26562df6775cSnicm 	return;
26572df6775cSnicm 
26582df6775cSnicm bad:
26592df6775cSnicm 	log_debug("bad OSC 8 %s", p);
26602df6775cSnicm 	free(id);
26612df6775cSnicm }
26622df6775cSnicm 
2663d21788ceSnicm /*
2664d21788ceSnicm  * Get a client with a foreground for the pane. There isn't much to choose
2665d21788ceSnicm  * between them so just use the first.
2666d21788ceSnicm  */
2667d21788ceSnicm static int
2668d21788ceSnicm input_get_fg_client(struct window_pane *wp)
2669d21788ceSnicm {
2670d21788ceSnicm 	struct window	*w = wp->window;
2671d21788ceSnicm 	struct client	*loop;
2672d21788ceSnicm 
2673d21788ceSnicm 	TAILQ_FOREACH(loop, &clients, entry) {
2674d21788ceSnicm 		if (loop->flags & CLIENT_UNATTACHEDFLAGS)
2675d21788ceSnicm 			continue;
2676d21788ceSnicm 		if (loop->session == NULL || !session_has(loop->session, w))
2677d21788ceSnicm 			continue;
2678d21788ceSnicm 		if (loop->tty.fg == -1)
2679d21788ceSnicm 			continue;
2680d21788ceSnicm 		return (loop->tty.fg);
2681d21788ceSnicm 	}
2682d21788ceSnicm 	return (-1);
2683d21788ceSnicm }
2684d21788ceSnicm 
2685d21788ceSnicm /* Get a client with a background for the pane. */
2686d21788ceSnicm static int
2687d21788ceSnicm input_get_bg_client(struct window_pane *wp)
2688d21788ceSnicm {
2689d21788ceSnicm 	struct window	*w = wp->window;
2690d21788ceSnicm 	struct client	*loop;
2691d21788ceSnicm 
2692d21788ceSnicm 	TAILQ_FOREACH(loop, &clients, entry) {
2693d21788ceSnicm 		if (loop->flags & CLIENT_UNATTACHEDFLAGS)
2694d21788ceSnicm 			continue;
2695d21788ceSnicm 		if (loop->session == NULL || !session_has(loop->session, w))
2696d21788ceSnicm 			continue;
2697d21788ceSnicm 		if (loop->tty.bg == -1)
2698d21788ceSnicm 			continue;
2699d21788ceSnicm 		return (loop->tty.bg);
2700d21788ceSnicm 	}
2701d21788ceSnicm 	return (-1);
2702d21788ceSnicm }
2703d21788ceSnicm 
2704891e2565Snicm /*
2705891e2565Snicm  * If any control mode client exists that has provided a bg color, return it.
2706891e2565Snicm  * Otherwise, return -1.
2707891e2565Snicm  */
2708891e2565Snicm static int
2709891e2565Snicm input_get_bg_control_client(struct window_pane *wp)
2710891e2565Snicm {
2711891e2565Snicm 	struct client	*c;
2712891e2565Snicm 
2713891e2565Snicm 	if (wp->control_bg == -1)
2714891e2565Snicm 		return (-1);
2715891e2565Snicm 
2716891e2565Snicm 	TAILQ_FOREACH(c, &clients, entry) {
2717891e2565Snicm 		if (c->flags & CLIENT_CONTROL)
2718891e2565Snicm 			return (wp->control_bg);
2719891e2565Snicm 	}
2720891e2565Snicm 	return (-1);
2721891e2565Snicm }
2722891e2565Snicm 
2723891e2565Snicm /*
2724891e2565Snicm  * If any control mode client exists that has provided a fg color, return it.
2725891e2565Snicm  * Otherwise, return -1.
2726891e2565Snicm  */
2727891e2565Snicm static int
2728891e2565Snicm input_get_fg_control_client(struct window_pane *wp)
2729891e2565Snicm {
2730891e2565Snicm 	struct client	*c;
2731891e2565Snicm 
2732891e2565Snicm 	if (wp->control_fg == -1)
2733891e2565Snicm 		return (-1);
2734891e2565Snicm 
2735891e2565Snicm 	TAILQ_FOREACH(c, &clients, entry) {
2736891e2565Snicm 		if (c->flags & CLIENT_CONTROL)
2737891e2565Snicm 			return (wp->control_fg);
2738891e2565Snicm 	}
2739891e2565Snicm 	return (-1);
2740891e2565Snicm }
2741891e2565Snicm 
27427a3e72b5Snicm /* Handle the OSC 10 sequence for setting and querying foreground colour. */
2743681fc18fSnicm static void
274490866723Snicm input_osc_10(struct input_ctx *ictx, const char *p)
2745681fc18fSnicm {
274690866723Snicm 	struct window_pane	*wp = ictx->wp;
27477a3e72b5Snicm 	struct grid_cell	 defaults;
2748e68ccaeaSnicm 	int			 c;
2749681fc18fSnicm 
27507a3e72b5Snicm 	if (strcmp(p, "?") == 0) {
2751d21788ceSnicm 		if (wp == NULL)
2752d21788ceSnicm 			return;
2753891e2565Snicm 		c = input_get_fg_control_client(wp);
2754891e2565Snicm 		if (c == -1) {
27557a3e72b5Snicm 			tty_default_colours(&defaults, wp);
2756d21788ceSnicm 			if (COLOUR_DEFAULT(defaults.fg))
2757d21788ceSnicm 				c = input_get_fg_client(wp);
2758d21788ceSnicm 			else
2759d21788ceSnicm 				c = defaults.fg;
2760891e2565Snicm 		}
2761d21788ceSnicm 		input_osc_colour_reply(ictx, 10, c);
2762c2600de8Snicm 		return;
27637a3e72b5Snicm 	}
2764c2600de8Snicm 
2765d21788ceSnicm 	if ((c = colour_parseX11(p)) == -1) {
2766681fc18fSnicm 		log_debug("bad OSC 10: %s", p);
276733a1e283Snicm 		return;
276833a1e283Snicm 	}
276944f8884cSnicm 	if (ictx->palette != NULL) {
277033a1e283Snicm 		ictx->palette->fg = c;
277133a1e283Snicm 		if (wp != NULL)
277233a1e283Snicm 			wp->flags |= PANE_STYLECHANGED;
277333a1e283Snicm 		screen_write_fullredraw(&ictx->ctx);
2774681fc18fSnicm 	}
277544f8884cSnicm }
2776681fc18fSnicm 
27771db1a6bbSnicm /* Handle the OSC 110 sequence for resetting foreground colour. */
2778e68ccaeaSnicm static void
2779e68ccaeaSnicm input_osc_110(struct input_ctx *ictx, const char *p)
2780e68ccaeaSnicm {
2781e68ccaeaSnicm 	struct window_pane	*wp = ictx->wp;
2782e68ccaeaSnicm 
2783e68ccaeaSnicm 	if (*p != '\0')
2784e68ccaeaSnicm 		return;
278544f8884cSnicm 	if (ictx->palette != NULL) {
278633a1e283Snicm 		ictx->palette->fg = 8;
278733a1e283Snicm 		if (wp != NULL)
278833a1e283Snicm 			wp->flags |= PANE_STYLECHANGED;
278933a1e283Snicm 		screen_write_fullredraw(&ictx->ctx);
2790e68ccaeaSnicm 	}
279144f8884cSnicm }
2792e68ccaeaSnicm 
27937a3e72b5Snicm /* Handle the OSC 11 sequence for setting and querying background colour. */
2794681fc18fSnicm static void
279590866723Snicm input_osc_11(struct input_ctx *ictx, const char *p)
2796681fc18fSnicm {
279790866723Snicm 	struct window_pane	*wp = ictx->wp;
27987a3e72b5Snicm 	struct grid_cell	 defaults;
2799e68ccaeaSnicm 	int			 c;
2800681fc18fSnicm 
28017a3e72b5Snicm 	if (strcmp(p, "?") == 0) {
2802d21788ceSnicm 		if (wp == NULL)
2803d21788ceSnicm 			return;
2804891e2565Snicm 		c = input_get_bg_control_client(wp);
2805891e2565Snicm 		if (c == -1) {
28067a3e72b5Snicm 			tty_default_colours(&defaults, wp);
2807d21788ceSnicm 			if (COLOUR_DEFAULT(defaults.bg))
2808d21788ceSnicm 				c = input_get_bg_client(wp);
2809d21788ceSnicm 			else
2810d21788ceSnicm 				c = defaults.bg;
2811891e2565Snicm 		}
2812d21788ceSnicm 		input_osc_colour_reply(ictx, 11, c);
2813c2600de8Snicm 		return;
28147a3e72b5Snicm 	}
2815c2600de8Snicm 
2816d21788ceSnicm 	if ((c = colour_parseX11(p)) == -1) {
2817681fc18fSnicm 		log_debug("bad OSC 11: %s", p);
281833a1e283Snicm 		return;
281933a1e283Snicm 	}
282044f8884cSnicm 	if (ictx->palette != NULL) {
282133a1e283Snicm 		ictx->palette->bg = c;
282233a1e283Snicm 		if (wp != NULL)
282333a1e283Snicm 			wp->flags |= PANE_STYLECHANGED;
282433a1e283Snicm 		screen_write_fullredraw(&ictx->ctx);
2825681fc18fSnicm 	}
282644f8884cSnicm }
2827681fc18fSnicm 
2828e68ccaeaSnicm /* Handle the OSC 111 sequence for resetting background colour. */
2829e68ccaeaSnicm static void
2830e68ccaeaSnicm input_osc_111(struct input_ctx *ictx, const char *p)
2831e68ccaeaSnicm {
2832e68ccaeaSnicm 	struct window_pane	*wp = ictx->wp;
2833e68ccaeaSnicm 
2834e68ccaeaSnicm 	if (*p != '\0')
2835e68ccaeaSnicm 		return;
283644f8884cSnicm 	if (ictx->palette != NULL) {
283733a1e283Snicm 		ictx->palette->bg = 8;
283833a1e283Snicm 		if (wp != NULL)
283933a1e283Snicm 			wp->flags |= PANE_STYLECHANGED;
284033a1e283Snicm 		screen_write_fullredraw(&ictx->ctx);
2841e68ccaeaSnicm 	}
284244f8884cSnicm }
2843e68ccaeaSnicm 
28441db1a6bbSnicm /* Handle the OSC 12 sequence for setting and querying cursor colour. */
28451db1a6bbSnicm static void
28461db1a6bbSnicm input_osc_12(struct input_ctx *ictx, const char *p)
28471db1a6bbSnicm {
28481db1a6bbSnicm 	struct window_pane	*wp = ictx->wp;
28491db1a6bbSnicm 	int			 c;
28501db1a6bbSnicm 
28511db1a6bbSnicm 	if (strcmp(p, "?") == 0) {
28521db1a6bbSnicm 		if (wp != NULL) {
28531db1a6bbSnicm 			c = ictx->ctx.s->ccolour;
28541db1a6bbSnicm 			if (c == -1)
28551db1a6bbSnicm 				c = ictx->ctx.s->default_ccolour;
28561db1a6bbSnicm 			input_osc_colour_reply(ictx, 12, c);
28571db1a6bbSnicm 		}
28581db1a6bbSnicm 		return;
28591db1a6bbSnicm 	}
28601db1a6bbSnicm 
2861d21788ceSnicm 	if ((c = colour_parseX11(p)) == -1) {
28621db1a6bbSnicm 		log_debug("bad OSC 12: %s", p);
28631db1a6bbSnicm 		return;
28641db1a6bbSnicm 	}
28651db1a6bbSnicm 	screen_set_cursor_colour(ictx->ctx.s, c);
28661db1a6bbSnicm }
28671db1a6bbSnicm 
28681db1a6bbSnicm /* Handle the OSC 112 sequence for resetting cursor colour. */
28691db1a6bbSnicm static void
28701db1a6bbSnicm input_osc_112(struct input_ctx *ictx, const char *p)
28711db1a6bbSnicm {
28721db1a6bbSnicm 	if (*p == '\0') /* no arguments allowed */
28731db1a6bbSnicm 		screen_set_cursor_colour(ictx->ctx.s, -1);
28741db1a6bbSnicm }
28751db1a6bbSnicm 
2876cbbd91a4Snicm /* Handle the OSC 133 sequence. */
2877cbbd91a4Snicm static void
2878cbbd91a4Snicm input_osc_133(struct input_ctx *ictx, const char *p)
2879cbbd91a4Snicm {
2880cbbd91a4Snicm 	struct grid		*gd = ictx->ctx.s->grid;
2881cbbd91a4Snicm 	u_int			 line = ictx->ctx.s->cy + gd->hsize;
2882cbbd91a4Snicm 	struct grid_line	*gl;
2883cbbd91a4Snicm 
2884cbbd91a4Snicm 	if (line > gd->hsize + gd->sy - 1)
2885cbbd91a4Snicm 		return;
2886cbbd91a4Snicm 	gl = grid_get_line(gd, line);
2887cbbd91a4Snicm 
2888cbbd91a4Snicm 	switch (*p) {
2889cbbd91a4Snicm 	case 'A':
2890cbbd91a4Snicm 		gl->flags |= GRID_LINE_START_PROMPT;
2891cbbd91a4Snicm 		break;
2892e49f8566Snicm 	case 'C':
2893e49f8566Snicm 		gl->flags |= GRID_LINE_START_OUTPUT;
2894e49f8566Snicm 		break;
2895cbbd91a4Snicm 	}
2896cbbd91a4Snicm }
28971db1a6bbSnicm 
2898f7e94a12Snicm /* Handle the OSC 52 sequence for setting the clipboard. */
2899f7e94a12Snicm static void
290090866723Snicm input_osc_52(struct input_ctx *ictx, const char *p)
2901f7e94a12Snicm {
290290866723Snicm 	struct window_pane	*wp = ictx->wp;
2903f7e94a12Snicm 	char			*end;
2904f9bfc3f8Snicm 	const char		*buf = NULL;
2905f9bfc3f8Snicm 	size_t			 len = 0;
2906f7e94a12Snicm 	u_char			*out;
29070c1f54ebSnicm 	int			 outlen, state;
2908f7e94a12Snicm 	struct screen_write_ctx	 ctx;
290990866723Snicm 	struct paste_buffer	*pb;
29101b09dd8dSnicm 	const char*              allow = "cpqs01234567";
2911a97778adSnicm 	char                     flags[sizeof "cpqs01234567"] = "";
29121b09dd8dSnicm 	u_int			 i, j = 0;
2913f7e94a12Snicm 
291429ebed37Snicm 	if (wp == NULL)
291529ebed37Snicm 		return;
29160c1f54ebSnicm 	state = options_get_number(global_options, "set-clipboard");
29170c1f54ebSnicm 	if (state != 2)
29180c1f54ebSnicm 		return;
29190c1f54ebSnicm 
2920f7e94a12Snicm 	if ((end = strchr(p, ';')) == NULL)
2921f7e94a12Snicm 		return;
2922f7e94a12Snicm 	end++;
2923f7e94a12Snicm 	if (*end == '\0')
2924f7e94a12Snicm 		return;
292590866723Snicm 	log_debug("%s: %s", __func__, end);
292690866723Snicm 
29271b09dd8dSnicm 	for (i = 0; p + i != end; i++) {
29281b09dd8dSnicm 		if (strchr(allow, p[i]) != NULL && strchr(flags, p[i]) == NULL)
29291b09dd8dSnicm 			flags[j++] = p[i];
29301b09dd8dSnicm 	}
29311b09dd8dSnicm 	log_debug("%s: %.*s %s", __func__, (int)(end - p - 1), p, flags);
29321b09dd8dSnicm 
293390866723Snicm 	if (strcmp(end, "?") == 0) {
2934f9bfc3f8Snicm 		if ((pb = paste_get_top(NULL)) != NULL)
293590866723Snicm 			buf = paste_buffer_data(pb, &len);
293690866723Snicm 		if (ictx->input_end == INPUT_END_BEL)
2937f9bfc3f8Snicm 			input_reply_clipboard(ictx->event, buf, len, "\007");
293890866723Snicm 		else
2939f9bfc3f8Snicm 			input_reply_clipboard(ictx->event, buf, len, "\033\\");
294090866723Snicm 		return;
294190866723Snicm 	}
2942f7e94a12Snicm 
2943f7e94a12Snicm 	len = (strlen(end) / 4) * 3;
2944f7e94a12Snicm 	if (len == 0)
2945f7e94a12Snicm 		return;
2946f7e94a12Snicm 
2947f7e94a12Snicm 	out = xmalloc(len);
2948f7e94a12Snicm 	if ((outlen = b64_pton(end, out, len)) == -1) {
2949f7e94a12Snicm 		free(out);
2950f7e94a12Snicm 		return;
2951f7e94a12Snicm 	}
2952f7e94a12Snicm 
295383e83a91Snicm 	screen_write_start_pane(&ctx, wp, NULL);
29541b09dd8dSnicm 	screen_write_setselection(&ctx, flags, out, outlen);
2955f7e94a12Snicm 	screen_write_stop(&ctx);
29568c303b1fSnicm 	notify_pane("pane-set-clipboard", wp);
29570c1f54ebSnicm 
29584aafca52Snicm 	paste_add(NULL, out, outlen);
2959f7e94a12Snicm }
2960f7e94a12Snicm 
2961e16c1698Snicm /* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
2962e16c1698Snicm static void
296390866723Snicm input_osc_104(struct input_ctx *ictx, const char *p)
2964e16c1698Snicm {
2965e16c1698Snicm 	char	*copy, *s;
2966e16c1698Snicm 	long	 idx;
296733a1e283Snicm 	int	 bad = 0, redraw = 0;
296829ebed37Snicm 
2969e16c1698Snicm 	if (*p == '\0') {
297033a1e283Snicm 		colour_palette_clear(ictx->palette);
297133a1e283Snicm 		screen_write_fullredraw(&ictx->ctx);
2972e16c1698Snicm 		return;
2973e16c1698Snicm 	}
2974e16c1698Snicm 
2975e16c1698Snicm 	copy = s = xstrdup(p);
2976e16c1698Snicm 	while (*s != '\0') {
2977e16c1698Snicm 		idx = strtol(s, &s, 10);
297833a1e283Snicm 		if (*s != '\0' && *s != ';') {
297933a1e283Snicm 			bad = 1;
298033a1e283Snicm 			break;
298133a1e283Snicm 		}
298233a1e283Snicm 		if (idx < 0 || idx >= 256) {
298333a1e283Snicm 			bad = 1;
298433a1e283Snicm 			break;
298533a1e283Snicm 		}
298633a1e283Snicm 		if (colour_palette_set(ictx->palette, idx, -1))
298733a1e283Snicm 			redraw = 1;
2988e16c1698Snicm 		if (*s == ';')
2989e16c1698Snicm 			s++;
2990e16c1698Snicm 	}
299133a1e283Snicm 	if (bad)
2992e16c1698Snicm 		log_debug("bad OSC 104: %s", p);
299333a1e283Snicm 	if (redraw)
299433a1e283Snicm 		screen_write_fullredraw(&ictx->ctx);
2995e16c1698Snicm 	free(copy);
2996e16c1698Snicm }
2997f9bfc3f8Snicm 
2998f9bfc3f8Snicm void
2999f9bfc3f8Snicm input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len,
3000f9bfc3f8Snicm     const char *end)
3001f9bfc3f8Snicm {
3002f9bfc3f8Snicm 	char	*out = NULL;
3003e3eeb0f8Snicm 	int	 outlen = 0;
3004f9bfc3f8Snicm 
3005f9bfc3f8Snicm 	if (buf != NULL && len != 0) {
3006e3eeb0f8Snicm 		if (len >= ((size_t)INT_MAX * 3 / 4) - 1)
3007e3eeb0f8Snicm 			return;
3008f9bfc3f8Snicm 		outlen = 4 * ((len + 2) / 3) + 1;
3009f9bfc3f8Snicm 		out = xmalloc(outlen);
3010f9bfc3f8Snicm 		if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) {
3011f9bfc3f8Snicm 			free(out);
3012f9bfc3f8Snicm 			return;
3013f9bfc3f8Snicm 		}
3014f9bfc3f8Snicm 	}
3015f9bfc3f8Snicm 
3016f9bfc3f8Snicm 	bufferevent_write(bev, "\033]52;;", 6);
3017f9bfc3f8Snicm 	if (outlen != 0)
3018f9bfc3f8Snicm 		bufferevent_write(bev, out, outlen);
3019f9bfc3f8Snicm 	bufferevent_write(bev, end, strlen(end));
3020f9bfc3f8Snicm 	free(out);
3021f9bfc3f8Snicm }
3022*d5f1c1a5Snicm 
3023*d5f1c1a5Snicm /* Set input buffer size. */
3024*d5f1c1a5Snicm void
3025*d5f1c1a5Snicm input_set_buffer_size(size_t buffer_size)
3026*d5f1c1a5Snicm {
3027*d5f1c1a5Snicm 	log_debug("%s: %lu -> %lu", __func__, input_buffer_size, buffer_size);
3028*d5f1c1a5Snicm 	input_buffer_size = buffer_size;
3029*d5f1c1a5Snicm }
3030