input.c revision 1.45
1/* $OpenBSD: input.c,v 1.45 2012/01/21 08:10:21 nicm Exp $ */
2
3/*
4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20
21#include <stdlib.h>
22#include <string.h>
23
24#include "tmux.h"
25
26/*
27 * Based on the description by Paul Williams at:
28 *
29 * http://vt100.net/emu/dec_ansi_parser
30 *
31 * With the following changes:
32 *
33 * - 7-bit only.
34 *
35 * - Support for UTF-8.
36 *
37 * - OSC (but not APC) may be terminated by \007 as well as ST.
38 *
39 * - A state for APC similar to OSC. Some terminals appear to use this to set
40 *   the title.
41 *
42 * - A state for the screen \033k...\033\\ sequence to rename a window. This is
43 *   pretty stupid but not supporting it is more trouble than it is worth.
44 *
45 * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
46 *   be passed to the underlying teminal(s).
47 */
48
49/* Helper functions. */
50int	input_split(struct input_ctx *);
51int	input_get(struct input_ctx *, u_int, int, int);
52void	input_reply(struct input_ctx *, const char *, ...);
53
54/* Transition entry/exit handlers. */
55void	input_clear(struct input_ctx *);
56void	input_enter_osc(struct input_ctx *);
57void	input_exit_osc(struct input_ctx *);
58void	input_enter_apc(struct input_ctx *);
59void	input_exit_apc(struct input_ctx *);
60void	input_enter_rename(struct input_ctx *);
61void	input_exit_rename(struct input_ctx *);
62
63/* Input state handlers. */
64int	input_print(struct input_ctx *);
65int	input_intermediate(struct input_ctx *);
66int	input_parameter(struct input_ctx *);
67int	input_input(struct input_ctx *);
68int	input_c0_dispatch(struct input_ctx *);
69int	input_esc_dispatch(struct input_ctx *);
70int	input_csi_dispatch(struct input_ctx *);
71void	input_csi_dispatch_sgr(struct input_ctx *);
72int	input_dcs_dispatch(struct input_ctx *);
73int	input_utf8_open(struct input_ctx *);
74int	input_utf8_add(struct input_ctx *);
75int	input_utf8_close(struct input_ctx *);
76
77/* Command table comparison function. */
78int	input_table_compare(const void *, const void *);
79
80/* Command table entry. */
81struct input_table_entry {
82	int		ch;
83	const char     *interm;
84	int		type;
85};
86
87/* Escape commands. */
88enum input_esc_type {
89	INPUT_ESC_DECALN,
90	INPUT_ESC_DECKPAM,
91	INPUT_ESC_DECKPNM,
92	INPUT_ESC_DECRC,
93	INPUT_ESC_DECSC,
94	INPUT_ESC_HTS,
95	INPUT_ESC_IND,
96	INPUT_ESC_NEL,
97	INPUT_ESC_RI,
98	INPUT_ESC_RIS,
99	INPUT_ESC_SCSOFF_G0,
100	INPUT_ESC_SCSON_G0,
101};
102
103/* Escape command table. */
104const struct input_table_entry input_esc_table[] = {
105	{ '0', "(", INPUT_ESC_SCSOFF_G0 },
106	{ '7', "",  INPUT_ESC_DECSC },
107	{ '8', "",  INPUT_ESC_DECRC },
108	{ '8', "#", INPUT_ESC_DECALN },
109	{ '=', "",  INPUT_ESC_DECKPAM },
110	{ '>', "",  INPUT_ESC_DECKPNM },
111	{ 'B', "(", INPUT_ESC_SCSON_G0 },
112	{ 'D', "",  INPUT_ESC_IND },
113	{ 'E', "",  INPUT_ESC_NEL },
114	{ 'H', "",  INPUT_ESC_HTS },
115	{ 'M', "",  INPUT_ESC_RI },
116	{ 'c', "",  INPUT_ESC_RIS },
117};
118
119/* Control (CSI) commands. */
120enum input_csi_type {
121	INPUT_CSI_CBT,
122	INPUT_CSI_CNL,
123	INPUT_CSI_CPL,
124	INPUT_CSI_CUB,
125	INPUT_CSI_CUD,
126	INPUT_CSI_CUF,
127	INPUT_CSI_CUP,
128	INPUT_CSI_CUU,
129	INPUT_CSI_DA,
130	INPUT_CSI_DCH,
131	INPUT_CSI_DECSCUSR,
132	INPUT_CSI_DECSTBM,
133	INPUT_CSI_DL,
134	INPUT_CSI_DSR,
135	INPUT_CSI_ED,
136	INPUT_CSI_EL,
137	INPUT_CSI_HPA,
138	INPUT_CSI_ICH,
139	INPUT_CSI_IL,
140	INPUT_CSI_RCP,
141	INPUT_CSI_RM,
142	INPUT_CSI_RM_PRIVATE,
143	INPUT_CSI_SCP,
144	INPUT_CSI_SGR,
145	INPUT_CSI_SM,
146	INPUT_CSI_SM_PRIVATE,
147	INPUT_CSI_TBC,
148	INPUT_CSI_VPA,
149};
150
151/* Control (CSI) command table. */
152const struct input_table_entry input_csi_table[] = {
153	{ '@', "",  INPUT_CSI_ICH },
154	{ 'A', "",  INPUT_CSI_CUU },
155	{ 'B', "",  INPUT_CSI_CUD },
156	{ 'C', "",  INPUT_CSI_CUF },
157	{ 'D', "",  INPUT_CSI_CUB },
158	{ 'E', "",  INPUT_CSI_CNL },
159	{ 'F', "",  INPUT_CSI_CPL },
160	{ 'G', "",  INPUT_CSI_HPA },
161	{ 'H', "",  INPUT_CSI_CUP },
162	{ 'J', "",  INPUT_CSI_ED },
163	{ 'K', "",  INPUT_CSI_EL },
164	{ 'L', "",  INPUT_CSI_IL },
165	{ 'M', "",  INPUT_CSI_DL },
166	{ 'P', "",  INPUT_CSI_DCH },
167	{ 'Z', "",  INPUT_CSI_CBT },
168	{ 'c', "",  INPUT_CSI_DA },
169	{ 'd', "",  INPUT_CSI_VPA },
170	{ 'f', "",  INPUT_CSI_CUP },
171	{ 'g', "",  INPUT_CSI_TBC },
172	{ 'h', "",  INPUT_CSI_SM },
173	{ 'h', "?", INPUT_CSI_SM_PRIVATE },
174	{ 'l', "",  INPUT_CSI_RM },
175	{ 'l', "?", INPUT_CSI_RM_PRIVATE },
176	{ 'm', "",  INPUT_CSI_SGR },
177	{ 'n', "",  INPUT_CSI_DSR },
178	{ 'q', " ", INPUT_CSI_DECSCUSR },
179	{ 'r', "",  INPUT_CSI_DECSTBM },
180	{ 's', "",  INPUT_CSI_SCP },
181	{ 'u', "",  INPUT_CSI_RCP },
182};
183
184/* Input transition. */
185struct input_transition {
186	int				first;
187	int				last;
188
189	int				(*handler)(struct input_ctx *);
190	const struct input_state       *state;
191};
192
193/* Input state. */
194struct input_state {
195	const char			*name;
196	void				(*enter)(struct input_ctx *);
197	void				(*exit)(struct input_ctx *);
198	const struct input_transition	*transitions;
199};
200
201/* State transitions available from all states. */
202#define INPUT_STATE_ANYWHERE \
203	{ 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
204	{ 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
205	{ 0x1b, 0x1b, NULL,		 &input_state_esc_enter }
206
207/* Forward declarations of state tables. */
208const struct input_transition input_state_ground_table[];
209const struct input_transition input_state_esc_enter_table[];
210const struct input_transition input_state_esc_intermediate_table[];
211const struct input_transition input_state_csi_enter_table[];
212const struct input_transition input_state_csi_parameter_table[];
213const struct input_transition input_state_csi_intermediate_table[];
214const struct input_transition input_state_csi_ignore_table[];
215const struct input_transition input_state_dcs_enter_table[];
216const struct input_transition input_state_dcs_parameter_table[];
217const struct input_transition input_state_dcs_intermediate_table[];
218const struct input_transition input_state_dcs_handler_table[];
219const struct input_transition input_state_dcs_escape_table[];
220const struct input_transition input_state_dcs_ignore_table[];
221const struct input_transition input_state_osc_string_table[];
222const struct input_transition input_state_apc_string_table[];
223const struct input_transition input_state_rename_string_table[];
224const struct input_transition input_state_consume_st_table[];
225const struct input_transition input_state_utf8_three_table[];
226const struct input_transition input_state_utf8_two_table[];
227const struct input_transition input_state_utf8_one_table[];
228
229/* ground state definition. */
230const struct input_state input_state_ground = {
231	"ground",
232	NULL, NULL,
233	input_state_ground_table
234};
235
236/* esc_enter state definition. */
237const struct input_state input_state_esc_enter = {
238	"esc_enter",
239	input_clear, NULL,
240	input_state_esc_enter_table
241};
242
243/* esc_intermediate state definition. */
244const struct input_state input_state_esc_intermediate = {
245	"esc_intermediate",
246	NULL, NULL,
247	input_state_esc_intermediate_table
248};
249
250/* csi_enter state definition. */
251const struct input_state input_state_csi_enter = {
252	"csi_enter",
253	input_clear, NULL,
254	input_state_csi_enter_table
255};
256
257/* csi_parameter state definition. */
258const struct input_state input_state_csi_parameter = {
259	"csi_parameter",
260	NULL, NULL,
261	input_state_csi_parameter_table
262};
263
264/* csi_intermediate state definition. */
265const struct input_state input_state_csi_intermediate = {
266	"csi_intermediate",
267	NULL, NULL,
268	input_state_csi_intermediate_table
269};
270
271/* csi_ignore state definition. */
272const struct input_state input_state_csi_ignore = {
273	"csi_ignore",
274	NULL, NULL,
275	input_state_csi_ignore_table
276};
277
278/* dcs_enter state definition. */
279const struct input_state input_state_dcs_enter = {
280	"dcs_enter",
281	input_clear, NULL,
282	input_state_dcs_enter_table
283};
284
285/* dcs_parameter state definition. */
286const struct input_state input_state_dcs_parameter = {
287	"dcs_parameter",
288	NULL, NULL,
289	input_state_dcs_parameter_table
290};
291
292/* dcs_intermediate state definition. */
293const struct input_state input_state_dcs_intermediate = {
294	"dcs_intermediate",
295	NULL, NULL,
296	input_state_dcs_intermediate_table
297};
298
299/* dcs_handler state definition. */
300const struct input_state input_state_dcs_handler = {
301	"dcs_handler",
302	NULL, NULL,
303	input_state_dcs_handler_table
304};
305
306/* dcs_escape state definition. */
307const struct input_state input_state_dcs_escape = {
308	"dcs_escape",
309	NULL, NULL,
310	input_state_dcs_escape_table
311};
312
313/* dcs_ignore state definition. */
314const struct input_state input_state_dcs_ignore = {
315	"dcs_ignore",
316	NULL, NULL,
317	input_state_dcs_ignore_table
318};
319
320/* osc_string state definition. */
321const struct input_state input_state_osc_string = {
322	"osc_string",
323	input_enter_osc, input_exit_osc,
324	input_state_osc_string_table
325};
326
327/* apc_string state definition. */
328const struct input_state input_state_apc_string = {
329	"apc_string",
330	input_enter_apc, input_exit_apc,
331	input_state_apc_string_table
332};
333
334/* rename_string state definition. */
335const struct input_state input_state_rename_string = {
336	"rename_string",
337	input_enter_rename, input_exit_rename,
338	input_state_rename_string_table
339};
340
341/* consume_st state definition. */
342const struct input_state input_state_consume_st = {
343	"consume_st",
344	NULL, NULL,
345	input_state_consume_st_table
346};
347
348/* utf8_three state definition. */
349const struct input_state input_state_utf8_three = {
350	"utf8_three",
351	NULL, NULL,
352	input_state_utf8_three_table
353};
354
355/* utf8_two state definition. */
356const struct input_state input_state_utf8_two = {
357	"utf8_two",
358	NULL, NULL,
359	input_state_utf8_two_table
360};
361
362/* utf8_one state definition. */
363const struct input_state input_state_utf8_one = {
364	"utf8_one",
365	NULL, NULL,
366	input_state_utf8_one_table
367};
368
369/* ground state table. */
370const struct input_transition input_state_ground_table[] = {
371	INPUT_STATE_ANYWHERE,
372
373	{ 0x00, 0x17, input_c0_dispatch, NULL },
374	{ 0x19, 0x19, input_c0_dispatch, NULL },
375	{ 0x1c, 0x1f, input_c0_dispatch, NULL },
376	{ 0x20, 0x7e, input_print,	 NULL },
377	{ 0x7f, 0x7f, NULL,		 NULL },
378	{ 0x80, 0xc1, input_print,	 NULL },
379	{ 0xc2, 0xdf, input_utf8_open,	 &input_state_utf8_one },
380	{ 0xe0, 0xef, input_utf8_open,	 &input_state_utf8_two },
381	{ 0xf0, 0xf4, input_utf8_open,	 &input_state_utf8_three },
382	{ 0xf5, 0xff, input_print,	 NULL },
383
384	{ -1, -1, NULL, NULL }
385};
386
387/* esc_enter state table. */
388const struct input_transition input_state_esc_enter_table[] = {
389	INPUT_STATE_ANYWHERE,
390
391	{ 0x00, 0x17, input_c0_dispatch,  NULL },
392	{ 0x19, 0x19, input_c0_dispatch,  NULL },
393	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
394	{ 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
395	{ 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
396	{ 0x50, 0x50, NULL,		  &input_state_dcs_enter },
397	{ 0x51, 0x57, input_esc_dispatch, &input_state_ground },
398	{ 0x58, 0x58, NULL,		  &input_state_consume_st },
399	{ 0x59, 0x59, input_esc_dispatch, &input_state_ground },
400	{ 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
401	{ 0x5b, 0x5b, NULL,		  &input_state_csi_enter },
402	{ 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
403	{ 0x5d, 0x5d, NULL,		  &input_state_osc_string },
404	{ 0x5e, 0x5e, NULL,		  &input_state_consume_st },
405	{ 0x5f, 0x5f, NULL,		  &input_state_apc_string },
406	{ 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
407	{ 0x6b, 0x6b, NULL,		  &input_state_rename_string },
408	{ 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
409	{ 0x7f, 0xff, NULL,		  NULL },
410
411	{ -1, -1, NULL, NULL }
412};
413
414/* esc_interm state table. */
415const struct input_transition input_state_esc_intermediate_table[] = {
416	INPUT_STATE_ANYWHERE,
417
418	{ 0x00, 0x17, input_c0_dispatch,  NULL },
419	{ 0x19, 0x19, input_c0_dispatch,  NULL },
420	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
421	{ 0x20, 0x2f, input_intermediate, NULL },
422	{ 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
423	{ 0x7f, 0xff, NULL,		  NULL },
424
425	{ -1, -1, NULL, NULL }
426};
427
428/* csi_enter state table. */
429const struct input_transition input_state_csi_enter_table[] = {
430	INPUT_STATE_ANYWHERE,
431
432	{ 0x00, 0x17, input_c0_dispatch,  NULL },
433	{ 0x19, 0x19, input_c0_dispatch,  NULL },
434	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
435	{ 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
436	{ 0x30, 0x39, input_parameter,	  &input_state_csi_parameter },
437	{ 0x3a, 0x3a, NULL,		  &input_state_csi_ignore },
438	{ 0x3b, 0x3b, input_parameter,	  &input_state_csi_parameter },
439	{ 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
440	{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
441	{ 0x7f, 0xff, NULL,		  NULL },
442
443	{ -1, -1, NULL, NULL }
444};
445
446/* csi_parameter state table. */
447const struct input_transition input_state_csi_parameter_table[] = {
448	INPUT_STATE_ANYWHERE,
449
450	{ 0x00, 0x17, input_c0_dispatch,  NULL },
451	{ 0x19, 0x19, input_c0_dispatch,  NULL },
452	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
453	{ 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
454	{ 0x30, 0x39, input_parameter,	  NULL },
455	{ 0x3a, 0x3a, NULL,		  &input_state_csi_ignore },
456	{ 0x3b, 0x3b, input_parameter,	  NULL },
457	{ 0x3c, 0x3f, NULL,		  &input_state_csi_ignore },
458	{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
459	{ 0x7f, 0xff, NULL,		  NULL },
460
461	{ -1, -1, NULL, NULL }
462};
463
464/* csi_intermediate state table. */
465const struct input_transition input_state_csi_intermediate_table[] = {
466	INPUT_STATE_ANYWHERE,
467
468	{ 0x00, 0x17, input_c0_dispatch,  NULL },
469	{ 0x19, 0x19, input_c0_dispatch,  NULL },
470	{ 0x1c, 0x1f, input_c0_dispatch,  NULL },
471	{ 0x20, 0x2f, input_intermediate, NULL },
472	{ 0x30, 0x3f, NULL,		  &input_state_csi_ignore },
473	{ 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
474	{ 0x7f, 0xff, NULL,		  NULL },
475
476	{ -1, -1, NULL, NULL }
477};
478
479/* csi_ignore state table. */
480const struct input_transition input_state_csi_ignore_table[] = {
481	INPUT_STATE_ANYWHERE,
482
483	{ 0x00, 0x17, input_c0_dispatch, NULL },
484	{ 0x19, 0x19, input_c0_dispatch, NULL },
485	{ 0x1c, 0x1f, input_c0_dispatch, NULL },
486	{ 0x20, 0x3f, NULL,		 NULL },
487	{ 0x40, 0x7e, NULL,		 &input_state_ground },
488	{ 0x7f, 0xff, NULL,		 NULL },
489
490	{ -1, -1, NULL, NULL }
491};
492
493/* dcs_enter state table. */
494const struct input_transition input_state_dcs_enter_table[] = {
495	INPUT_STATE_ANYWHERE,
496
497	{ 0x00, 0x17, NULL,		  NULL },
498	{ 0x19, 0x19, NULL,		  NULL },
499	{ 0x1c, 0x1f, NULL,		  NULL },
500	{ 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
501	{ 0x30, 0x39, input_parameter,	  &input_state_dcs_parameter },
502	{ 0x3a, 0x3a, NULL,		  &input_state_dcs_ignore },
503	{ 0x3b, 0x3b, input_parameter,	  &input_state_dcs_parameter },
504	{ 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
505	{ 0x40, 0x7e, input_input,	  &input_state_dcs_handler },
506	{ 0x7f, 0xff, NULL,		  NULL },
507
508	{ -1, -1, NULL, NULL }
509};
510
511/* dcs_parameter state table. */
512const struct input_transition input_state_dcs_parameter_table[] = {
513	INPUT_STATE_ANYWHERE,
514
515	{ 0x00, 0x17, NULL,		  NULL },
516	{ 0x19, 0x19, NULL,		  NULL },
517	{ 0x1c, 0x1f, NULL,		  NULL },
518	{ 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
519	{ 0x30, 0x39, input_parameter,	  NULL },
520	{ 0x3a, 0x3a, NULL,		  &input_state_dcs_ignore },
521	{ 0x3b, 0x3b, input_parameter,	  NULL },
522	{ 0x3c, 0x3f, NULL,		  &input_state_dcs_ignore },
523	{ 0x40, 0x7e, input_input,	  &input_state_dcs_handler },
524	{ 0x7f, 0xff, NULL,		  NULL },
525
526	{ -1, -1, NULL, NULL }
527};
528
529/* dcs_interm state table. */
530const struct input_transition input_state_dcs_intermediate_table[] = {
531	INPUT_STATE_ANYWHERE,
532
533	{ 0x00, 0x17, NULL,		  NULL },
534	{ 0x19, 0x19, NULL,		  NULL },
535	{ 0x1c, 0x1f, NULL,		  NULL },
536	{ 0x20, 0x2f, input_intermediate, NULL },
537	{ 0x30, 0x3f, NULL,		  &input_state_dcs_ignore },
538	{ 0x40, 0x7e, input_input,	  &input_state_dcs_handler },
539	{ 0x7f, 0xff, NULL,		  NULL },
540
541	{ -1, -1, NULL, NULL }
542};
543
544/* dcs_handler state table. */
545const struct input_transition input_state_dcs_handler_table[] = {
546	/* No INPUT_STATE_ANYWHERE */
547
548	{ 0x00, 0x1a, input_input,  NULL },
549	{ 0x1b, 0x1b, NULL,	    &input_state_dcs_escape },
550	{ 0x1c, 0xff, input_input,  NULL },
551
552	{ -1, -1, NULL, NULL }
553};
554
555/* dcs_escape state table. */
556const struct input_transition input_state_dcs_escape_table[] = {
557	/* No INPUT_STATE_ANYWHERE */
558
559	{ 0x00, 0x5b, input_input,	  &input_state_dcs_handler },
560	{ 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
561	{ 0x5d, 0xff, input_input,	  &input_state_dcs_handler },
562
563	{ -1, -1, NULL, NULL }
564};
565
566/* dcs_ignore state table. */
567const struct input_transition input_state_dcs_ignore_table[] = {
568	INPUT_STATE_ANYWHERE,
569
570	{ 0x00, 0x17, NULL,	    NULL },
571	{ 0x19, 0x19, NULL,	    NULL },
572	{ 0x1c, 0x1f, NULL,	    NULL },
573	{ 0x20, 0xff, NULL,	    NULL },
574
575	{ -1, -1, NULL, NULL }
576};
577
578/* osc_string state table. */
579const struct input_transition input_state_osc_string_table[] = {
580	INPUT_STATE_ANYWHERE,
581
582	{ 0x00, 0x06, NULL,	    NULL },
583	{ 0x07, 0x07, NULL,	    &input_state_ground },
584	{ 0x08, 0x17, NULL,	    NULL },
585	{ 0x19, 0x19, NULL,	    NULL },
586	{ 0x1c, 0x1f, NULL,	    NULL },
587	{ 0x20, 0xff, input_input,  NULL },
588
589	{ -1, -1, NULL, NULL }
590};
591
592/* apc_string state table. */
593const struct input_transition input_state_apc_string_table[] = {
594	INPUT_STATE_ANYWHERE,
595
596	{ 0x00, 0x17, NULL,	    NULL },
597	{ 0x19, 0x19, NULL,	    NULL },
598	{ 0x1c, 0x1f, NULL,	    NULL },
599	{ 0x20, 0xff, input_input,  NULL },
600
601	{ -1, -1, NULL, NULL }
602};
603
604/* rename_string state table. */
605const struct input_transition input_state_rename_string_table[] = {
606	INPUT_STATE_ANYWHERE,
607
608	{ 0x00, 0x17, NULL,	    NULL },
609	{ 0x19, 0x19, NULL,	    NULL },
610	{ 0x1c, 0x1f, NULL,	    NULL },
611	{ 0x20, 0xff, input_input,  NULL },
612
613	{ -1, -1, NULL, NULL }
614};
615
616/* consume_st state table. */
617const struct input_transition input_state_consume_st_table[] = {
618	INPUT_STATE_ANYWHERE,
619
620	{ 0x00, 0x17, NULL,	    NULL },
621	{ 0x19, 0x19, NULL,	    NULL },
622	{ 0x1c, 0x1f, NULL,	    NULL },
623	{ 0x20, 0xff, NULL,	    NULL },
624
625	{ -1, -1, NULL, NULL }
626};
627
628/* utf8_three state table. */
629const struct input_transition input_state_utf8_three_table[] = {
630	/* No INPUT_STATE_ANYWHERE */
631
632	{ 0x00, 0x7f, NULL,		&input_state_ground },
633	{ 0x80, 0xbf, input_utf8_add,	&input_state_utf8_two },
634	{ 0xc0, 0xff, NULL,		&input_state_ground },
635
636	{ -1, -1, NULL, NULL }
637};
638
639/* utf8_two state table. */
640const struct input_transition input_state_utf8_two_table[] = {
641	/* No INPUT_STATE_ANYWHERE */
642
643	{ 0x00, 0x7f, NULL,	      &input_state_ground },
644	{ 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
645	{ 0xc0, 0xff, NULL,	      &input_state_ground },
646
647	{ -1, -1, NULL, NULL }
648};
649
650/* utf8_one state table. */
651const struct input_transition input_state_utf8_one_table[] = {
652	/* No INPUT_STATE_ANYWHERE */
653
654	{ 0x00, 0x7f, NULL,		&input_state_ground },
655	{ 0x80, 0xbf, input_utf8_close, &input_state_ground },
656	{ 0xc0, 0xff, NULL,		&input_state_ground },
657
658	{ -1, -1, NULL, NULL }
659};
660
661/* Input table compare. */
662int
663input_table_compare(const void *key, const void *value)
664{
665	const struct input_ctx		*ictx = key;
666	const struct input_table_entry	*entry = value;
667
668	if (ictx->ch != entry->ch)
669		return (ictx->ch - entry->ch);
670	return (strcmp(ictx->interm_buf, entry->interm));
671}
672
673/* Initialise input parser. */
674void
675input_init(struct window_pane *wp)
676{
677	struct input_ctx	*ictx = &wp->ictx;
678
679	memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
680
681	memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell);
682	ictx->old_cx = 0;
683	ictx->old_cy = 0;
684
685	*ictx->interm_buf = '\0';
686	ictx->interm_len = 0;
687
688	*ictx->param_buf = '\0';
689	ictx->param_len = 0;
690
691	ictx->state = &input_state_ground;
692	ictx->flags = 0;
693}
694
695/* Destroy input parser. */
696void
697input_free(unused struct window_pane *wp)
698{
699}
700
701/* Parse input. */
702void
703input_parse(struct window_pane *wp)
704{
705	struct input_ctx		*ictx = &wp->ictx;
706	const struct input_transition	*itr;
707	struct evbuffer			*evb = wp->event->input;
708	u_char				*buf;
709	size_t				 len, off;
710
711	if (EVBUFFER_LENGTH(evb) == 0)
712		return;
713
714	wp->window->flags |= WINDOW_ACTIVITY;
715	wp->window->flags &= ~WINDOW_SILENCE;
716
717	/*
718	 * Open the screen. Use NULL wp if there is a mode set as don't want to
719	 * update the tty.
720	 */
721	if (wp->mode == NULL)
722		screen_write_start(&ictx->ctx, wp, &wp->base);
723	else
724		screen_write_start(&ictx->ctx, NULL, &wp->base);
725	ictx->wp = wp;
726
727	buf = EVBUFFER_DATA(evb);
728	len = EVBUFFER_LENGTH(evb);
729	off = 0;
730
731	/* Parse the input. */
732	while (off < len) {
733		ictx->ch = buf[off++];
734		log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
735
736		/* Find the transition. */
737		itr = ictx->state->transitions;
738		while (itr->first != -1 && itr->last != -1) {
739			if (ictx->ch >= itr->first && ictx->ch <= itr->last)
740				break;
741			itr++;
742		}
743		if (itr->first == -1 || itr->last == -1) {
744			/* No transition? Eh? */
745			fatalx("No transition from state!");
746		}
747
748		/*
749		 * Execute the handler, if any. Don't switch state if it
750		 * returns non-zero.
751		 */
752		if (itr->handler != NULL && itr->handler(ictx) != 0)
753			continue;
754
755		/* And switch state, if necessary. */
756		if (itr->state != NULL) {
757			if (ictx->state->exit != NULL)
758				ictx->state->exit(ictx);
759			ictx->state = itr->state;
760			if (ictx->state->enter != NULL)
761				ictx->state->enter(ictx);
762		}
763	}
764
765	/* Close the screen. */
766	screen_write_stop(&ictx->ctx);
767
768	evbuffer_drain(evb, len);
769}
770
771/* Split the parameter list (if any). */
772int
773input_split(struct input_ctx *ictx)
774
775{
776	const char	*errstr;
777	char		*ptr, *out;
778	int		 n;
779
780	ictx->param_list_len = 0;
781	if (ictx->param_len == 0)
782		return (0);
783
784	ptr = ictx->param_buf;
785	while ((out = strsep(&ptr, ";")) != NULL) {
786		if (*out == '\0')
787			n = -1;
788		else {
789			n = strtonum(out, 0, INT_MAX, &errstr);
790			if (errstr != NULL)
791				return (-1);
792		}
793
794		ictx->param_list[ictx->param_list_len++] = n;
795		if (ictx->param_list_len == nitems(ictx->param_list))
796			return (-1);
797	}
798
799	return (0);
800}
801
802/* Get an argument or return default value. */
803int
804input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
805{
806	int	retval;
807
808	if (validx >= ictx->param_list_len)
809	    return (defval);
810
811	retval = ictx->param_list[validx];
812	if (retval == -1)
813		return (defval);
814	if (retval < minval)
815		return (minval);
816	return (retval);
817}
818
819/* Reply to terminal query. */
820void
821input_reply(struct input_ctx *ictx, const char *fmt, ...)
822{
823	va_list	ap;
824	char   *reply;
825
826	va_start(ap, fmt);
827	vasprintf(&reply, fmt, ap);
828	va_end(ap);
829
830	bufferevent_write(ictx->wp->event, reply, strlen(reply));
831	xfree(reply);
832}
833
834/* Clear saved state. */
835void
836input_clear(struct input_ctx *ictx)
837{
838	*ictx->interm_buf = '\0';
839	ictx->interm_len = 0;
840
841	*ictx->param_buf = '\0';
842	ictx->param_len = 0;
843
844	*ictx->input_buf = '\0';
845	ictx->input_len = 0;
846
847	ictx->flags &= ~INPUT_DISCARD;
848}
849
850/* Output this character to the screen. */
851int
852input_print(struct input_ctx *ictx)
853{
854	ictx->cell.data = ictx->ch;
855	screen_write_cell(&ictx->ctx, &ictx->cell, NULL);
856
857	return (0);
858}
859
860/* Collect intermediate string. */
861int
862input_intermediate(struct input_ctx *ictx)
863{
864	if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
865		ictx->flags |= INPUT_DISCARD;
866	else {
867		ictx->interm_buf[ictx->interm_len++] = ictx->ch;
868		ictx->interm_buf[ictx->interm_len] = '\0';
869	}
870
871	return (0);
872}
873
874/* Collect parameter string. */
875int
876input_parameter(struct input_ctx *ictx)
877{
878	if (ictx->param_len == (sizeof ictx->param_buf) - 1)
879		ictx->flags |= INPUT_DISCARD;
880	else {
881		ictx->param_buf[ictx->param_len++] = ictx->ch;
882		ictx->param_buf[ictx->param_len] = '\0';
883	}
884
885	return (0);
886}
887
888/* Collect input string. */
889int
890input_input(struct input_ctx *ictx)
891{
892	if (ictx->input_len == (sizeof ictx->input_buf) - 1)
893		ictx->flags |= INPUT_DISCARD;
894	else {
895		ictx->input_buf[ictx->input_len++] = ictx->ch;
896		ictx->input_buf[ictx->input_len] = '\0';
897	}
898
899	return (0);
900}
901
902/* Execute C0 control sequence. */
903int
904input_c0_dispatch(struct input_ctx *ictx)
905{
906	struct screen_write_ctx	*sctx = &ictx->ctx;
907	struct window_pane	*wp = ictx->wp;
908	struct screen		*s = sctx->s;
909
910	log_debug("%s: '%c", __func__, ictx->ch);
911
912	switch (ictx->ch) {
913	case '\000':	/* NUL */
914		break;
915	case '\007':	/* BEL */
916		wp->window->flags |= WINDOW_BELL;
917		break;
918	case '\010':	/* BS */
919		screen_write_backspace(sctx);
920		break;
921	case '\011':	/* HT */
922		/* Don't tab beyond the end of the line. */
923		if (s->cx >= screen_size_x(s) - 1)
924			break;
925
926		/* Find the next tab point, or use the last column if none. */
927		do {
928			s->cx++;
929			if (bit_test(s->tabs, s->cx))
930				break;
931		} while (s->cx < screen_size_x(s) - 1);
932		break;
933	case '\012':	/* LF */
934	case '\013':	/* VT */
935	case '\014':	/* FF */
936		screen_write_linefeed(sctx, 0);
937		break;
938	case '\015':	/* CR */
939		screen_write_carriagereturn(sctx);
940		break;
941	case '\016':	/* SO */
942		ictx->cell.attr |= GRID_ATTR_CHARSET;
943		break;
944	case '\017':	/* SI */
945		ictx->cell.attr &= ~GRID_ATTR_CHARSET;
946		break;
947	default:
948		log_debug("%s: unknown '%c'", __func__, ictx->ch);
949		break;
950	}
951
952	return (0);
953}
954
955/* Execute escape sequence. */
956int
957input_esc_dispatch(struct input_ctx *ictx)
958{
959	struct screen_write_ctx		*sctx = &ictx->ctx;
960	struct screen			*s = sctx->s;
961	struct input_table_entry	*entry;
962
963	if (ictx->flags & INPUT_DISCARD)
964		return (0);
965	log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
966
967	entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
968	    sizeof input_esc_table[0], input_table_compare);
969	if (entry == NULL) {
970		log_debug("%s: unknown '%c'", __func__, ictx->ch);
971		return (0);
972	}
973
974	switch (entry->type) {
975	case INPUT_ESC_RIS:
976		memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
977		memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
978		ictx->old_cx = 0;
979		ictx->old_cy = 0;
980
981		screen_write_reset(sctx->s);
982		break;
983	case INPUT_ESC_IND:
984		screen_write_linefeed(sctx, 0);
985		break;
986	case INPUT_ESC_NEL:
987		screen_write_carriagereturn(sctx);
988		screen_write_linefeed(sctx, 0);
989		break;
990	case INPUT_ESC_HTS:
991		if (s->cx < screen_size_x(s))
992			bit_set(s->tabs, s->cx);
993		break;
994	case INPUT_ESC_RI:
995		screen_write_reverseindex(sctx);
996		break;
997	case INPUT_ESC_DECKPAM:
998		screen_write_kkeypadmode(sctx, 1);
999		break;
1000	case INPUT_ESC_DECKPNM:
1001		screen_write_kkeypadmode(sctx, 0);
1002		break;
1003	case INPUT_ESC_DECSC:
1004		memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1005		ictx->old_cx = s->cx;
1006		ictx->old_cy = s->cy;
1007		break;
1008	case INPUT_ESC_DECRC:
1009		memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1010		screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1011		break;
1012	case INPUT_ESC_DECALN:
1013		screen_write_alignmenttest(sctx);
1014		break;
1015	case INPUT_ESC_SCSON_G0:
1016		/*
1017		 * Not really supported, but fake it up enough for those that
1018		 * use it to switch character sets (by redefining G0 to
1019		 * graphics set, rather than switching to G1).
1020		 */
1021		ictx->cell.attr &= ~GRID_ATTR_CHARSET;
1022		break;
1023	case INPUT_ESC_SCSOFF_G0:
1024		ictx->cell.attr |= GRID_ATTR_CHARSET;
1025		break;
1026	}
1027
1028	return (0);
1029}
1030
1031/* Execute control sequence. */
1032int
1033input_csi_dispatch(struct input_ctx *ictx)
1034{
1035	struct screen_write_ctx	       *sctx = &ictx->ctx;
1036	struct window_pane	       *wp = ictx->wp;
1037	struct screen		       *s = sctx->s;
1038	struct input_table_entry       *entry;
1039	int			 	n, m;
1040
1041	if (ictx->flags & INPUT_DISCARD)
1042		return (0);
1043	if (input_split(ictx) != 0)
1044		return (0);
1045	log_debug("%s: '%c' \"%s\" \"%s\"",
1046	    __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1047
1048	entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1049	    sizeof input_csi_table[0], input_table_compare);
1050	if (entry == NULL) {
1051		log_debug("%s: unknown '%c'", __func__, ictx->ch);
1052		return (0);
1053	}
1054
1055	switch (entry->type) {
1056	case INPUT_CSI_CBT:
1057		/* Find the previous tab point, n times. */
1058		n = input_get(ictx, 0, 1, 1);
1059		while (s->cx > 0 && n-- > 0) {
1060			do
1061				s->cx--;
1062			while (s->cx > 0 && !bit_test(s->tabs, s->cx));
1063		}
1064		break;
1065	case INPUT_CSI_CUB:
1066		screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1));
1067		break;
1068	case INPUT_CSI_CUD:
1069		screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1070		break;
1071	case INPUT_CSI_CUF:
1072		screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1));
1073		break;
1074	case INPUT_CSI_CUP:
1075		n = input_get(ictx, 0, 1, 1);
1076		m = input_get(ictx, 1, 1, 1);
1077		screen_write_cursormove(sctx, m - 1, n - 1);
1078		break;
1079	case INPUT_CSI_CUU:
1080		screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1081		break;
1082	case INPUT_CSI_CNL:
1083		screen_write_carriagereturn(sctx);
1084		screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1085		break;
1086	case INPUT_CSI_CPL:
1087		screen_write_carriagereturn(sctx);
1088		screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1089		break;
1090	case INPUT_CSI_DA:
1091		switch (input_get(ictx, 0, 0, 0)) {
1092		case 0:
1093			input_reply(ictx, "\033[?1;2c");
1094			break;
1095		default:
1096			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1097			break;
1098		}
1099		break;
1100	case INPUT_CSI_DCH:
1101		screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1));
1102		break;
1103	case INPUT_CSI_DECSTBM:
1104		n = input_get(ictx, 0, 1, 1);
1105		m = input_get(ictx, 1, 1, screen_size_y(s));
1106		screen_write_scrollregion(sctx, n - 1, m - 1);
1107		break;
1108	case INPUT_CSI_DL:
1109		screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1));
1110		break;
1111	case INPUT_CSI_DSR:
1112		switch (input_get(ictx, 0, 0, 0)) {
1113		case 5:
1114			input_reply(ictx, "\033[0n");
1115			break;
1116		case 6:
1117			input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1118			break;
1119		default:
1120			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1121			break;
1122		}
1123		break;
1124	case INPUT_CSI_ED:
1125		switch (input_get(ictx, 0, 0, 0)) {
1126		case 0:
1127			screen_write_clearendofscreen(sctx);
1128			break;
1129		case 1:
1130			screen_write_clearstartofscreen(sctx);
1131			break;
1132		case 2:
1133			screen_write_clearscreen(sctx);
1134			break;
1135		case 3:
1136			switch (input_get(ictx, 1, 0, 0)) {
1137			case 0:
1138				/*
1139				 * Linux console extension to clear history
1140				 * (for example before locking the screen).
1141				 */
1142				screen_write_clearhistory(sctx);
1143				break;
1144			}
1145			break;
1146		default:
1147			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1148			break;
1149		}
1150		break;
1151	case INPUT_CSI_EL:
1152		switch (input_get(ictx, 0, 0, 0)) {
1153		case 0:
1154			screen_write_clearendofline(sctx);
1155			break;
1156		case 1:
1157			screen_write_clearstartofline(sctx);
1158			break;
1159		case 2:
1160			screen_write_clearline(sctx);
1161			break;
1162		default:
1163			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1164			break;
1165		}
1166		break;
1167	case INPUT_CSI_HPA:
1168		n = input_get(ictx, 0, 1, 1);
1169		screen_write_cursormove(sctx, n - 1, s->cy);
1170		break;
1171	case INPUT_CSI_ICH:
1172		screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1));
1173		break;
1174	case INPUT_CSI_IL:
1175		screen_write_insertline(sctx, input_get(ictx, 0, 1, 1));
1176		break;
1177	case INPUT_CSI_RCP:
1178		memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1179		screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1180		break;
1181	case INPUT_CSI_RM:
1182		switch (input_get(ictx, 0, 0, -1)) {
1183		case 4:		/* IRM */
1184			screen_write_insertmode(&ictx->ctx, 0);
1185			break;
1186		default:
1187			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1188			break;
1189		}
1190		break;
1191	case INPUT_CSI_RM_PRIVATE:
1192		switch (input_get(ictx, 0, 0, -1)) {
1193		case 1:		/* GATM */
1194			screen_write_kcursormode(&ictx->ctx, 0);
1195			break;
1196		case 3:		/* DECCOLM */
1197			screen_write_cursormove(&ictx->ctx, 0, 0);
1198			screen_write_clearscreen(&ictx->ctx);
1199			break;
1200		case 25:	/* TCEM */
1201			screen_write_cursormode(&ictx->ctx, 0);
1202			break;
1203		case 1000:
1204		case 1001:
1205		case 1002:
1206		case 1003:
1207			screen_write_mousemode_off(&ictx->ctx);
1208			break;
1209		case 1005:
1210			screen_write_utf8mousemode(&ictx->ctx, 0);
1211			break;
1212		case 1049:
1213			window_pane_alternate_off(wp, &ictx->cell);
1214			break;
1215		default:
1216			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1217			break;
1218		}
1219		break;
1220	case INPUT_CSI_SCP:
1221		memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1222		ictx->old_cx = s->cx;
1223		ictx->old_cy = s->cy;
1224		break;
1225	case INPUT_CSI_SGR:
1226		input_csi_dispatch_sgr(ictx);
1227		break;
1228	case INPUT_CSI_SM:
1229		switch (input_get(ictx, 0, 0, -1)) {
1230		case 4:		/* IRM */
1231			screen_write_insertmode(&ictx->ctx, 1);
1232			break;
1233		default:
1234			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1235			break;
1236		}
1237		break;
1238	case INPUT_CSI_SM_PRIVATE:
1239		switch (input_get(ictx, 0, 0, -1)) {
1240		case 1:		/* GATM */
1241			screen_write_kcursormode(&ictx->ctx, 1);
1242			break;
1243		case 3:		/* DECCOLM */
1244			screen_write_cursormove(&ictx->ctx, 0, 0);
1245			screen_write_clearscreen(&ictx->ctx);
1246			break;
1247		case 25:	/* TCEM */
1248			screen_write_cursormode(&ictx->ctx, 1);
1249			break;
1250		case 1000:
1251			screen_write_mousemode_on(
1252			    &ictx->ctx, MODE_MOUSE_STANDARD);
1253			break;
1254		case 1002:
1255			screen_write_mousemode_on(
1256			    &ictx->ctx, MODE_MOUSE_BUTTON);
1257			break;
1258		case 1003:
1259			screen_write_mousemode_on(&ictx->ctx, MODE_MOUSE_ANY);
1260			break;
1261		case 1005:
1262			screen_write_utf8mousemode(&ictx->ctx, 1);
1263			break;
1264		case 1049:
1265			window_pane_alternate_on(wp, &ictx->cell);
1266			break;
1267		default:
1268			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1269			break;
1270		}
1271		break;
1272	case INPUT_CSI_TBC:
1273		switch (input_get(ictx, 0, 0, 0)) {
1274		case 0:
1275			if (s->cx < screen_size_x(s))
1276				bit_clear(s->tabs, s->cx);
1277			break;
1278		case 3:
1279			bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1280			break;
1281		default:
1282			log_debug("%s: unknown '%c'", __func__, ictx->ch);
1283			break;
1284		}
1285		break;
1286	case INPUT_CSI_VPA:
1287		n = input_get(ictx, 0, 1, 1);
1288		screen_write_cursormove(sctx, s->cx, n - 1);
1289		break;
1290	case INPUT_CSI_DECSCUSR:
1291		n = input_get(ictx, 0, 0, 0);
1292		screen_set_cursor_style(s, n);
1293		break;
1294	}
1295
1296	return (0);
1297}
1298
1299/* Handle CSI SGR. */
1300void
1301input_csi_dispatch_sgr(struct input_ctx *ictx)
1302{
1303	struct grid_cell	*gc = &ictx->cell;
1304	u_int			 i;
1305	int			 n, m;
1306	u_char			 attr;
1307
1308	if (ictx->param_list_len == 0) {
1309		attr = gc->attr;
1310		memcpy(gc, &grid_default_cell, sizeof *gc);
1311		gc->attr |= (attr & GRID_ATTR_CHARSET);
1312		return;
1313	}
1314
1315	for (i = 0; i < ictx->param_list_len; i++) {
1316		n = input_get(ictx, i, 0, 0);
1317
1318		if (n == 38 || n == 48) {
1319			i++;
1320			if (input_get(ictx, i, 0, -1) != 5)
1321				continue;
1322
1323			i++;
1324			m = input_get(ictx, i, 0, -1);
1325			if (m == -1) {
1326				if (n == 38) {
1327					gc->flags &= ~GRID_FLAG_FG256;
1328					gc->fg = 8;
1329				} else if (n == 48) {
1330					gc->flags &= ~GRID_FLAG_BG256;
1331					gc->bg = 8;
1332				}
1333
1334			} else {
1335				if (n == 38) {
1336					gc->flags |= GRID_FLAG_FG256;
1337					gc->fg = m;
1338				} else if (n == 48) {
1339					gc->flags |= GRID_FLAG_BG256;
1340					gc->bg = m;
1341				}
1342			}
1343			continue;
1344		}
1345
1346		switch (n) {
1347		case 0:
1348		case 10:
1349			attr = gc->attr;
1350			memcpy(gc, &grid_default_cell, sizeof *gc);
1351			gc->attr |= (attr & GRID_ATTR_CHARSET);
1352			break;
1353		case 1:
1354			gc->attr |= GRID_ATTR_BRIGHT;
1355			break;
1356		case 2:
1357			gc->attr |= GRID_ATTR_DIM;
1358			break;
1359		case 3:
1360			gc->attr |= GRID_ATTR_ITALICS;
1361			break;
1362		case 4:
1363			gc->attr |= GRID_ATTR_UNDERSCORE;
1364			break;
1365		case 5:
1366			gc->attr |= GRID_ATTR_BLINK;
1367			break;
1368		case 7:
1369			gc->attr |= GRID_ATTR_REVERSE;
1370			break;
1371		case 8:
1372			gc->attr |= GRID_ATTR_HIDDEN;
1373			break;
1374		case 22:
1375			gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1376			break;
1377		case 23:
1378			gc->attr &= ~GRID_ATTR_ITALICS;
1379			break;
1380		case 24:
1381			gc->attr &= ~GRID_ATTR_UNDERSCORE;
1382			break;
1383		case 25:
1384			gc->attr &= ~GRID_ATTR_BLINK;
1385			break;
1386		case 27:
1387			gc->attr &= ~GRID_ATTR_REVERSE;
1388			break;
1389		case 30:
1390		case 31:
1391		case 32:
1392		case 33:
1393		case 34:
1394		case 35:
1395		case 36:
1396		case 37:
1397			gc->flags &= ~GRID_FLAG_FG256;
1398			gc->fg = n - 30;
1399			break;
1400		case 39:
1401			gc->flags &= ~GRID_FLAG_FG256;
1402			gc->fg = 8;
1403			break;
1404		case 40:
1405		case 41:
1406		case 42:
1407		case 43:
1408		case 44:
1409		case 45:
1410		case 46:
1411		case 47:
1412			gc->flags &= ~GRID_FLAG_BG256;
1413			gc->bg = n - 40;
1414			break;
1415		case 49:
1416			gc->flags &= ~GRID_FLAG_BG256;
1417			gc->bg = 8;
1418			break;
1419		case 90:
1420		case 91:
1421		case 92:
1422		case 93:
1423		case 94:
1424		case 95:
1425		case 96:
1426		case 97:
1427			gc->flags &= ~GRID_FLAG_FG256;
1428			gc->fg = n;
1429			break;
1430		case 100:
1431		case 101:
1432		case 102:
1433		case 103:
1434		case 104:
1435		case 105:
1436		case 106:
1437		case 107:
1438			gc->flags &= ~GRID_FLAG_BG256;
1439			gc->bg = n;
1440			break;
1441		}
1442	}
1443}
1444
1445/* DCS terminator (ST) received. */
1446int
1447input_dcs_dispatch(struct input_ctx *ictx)
1448{
1449	const char	prefix[] = "tmux;";
1450	const u_int	prefix_len = (sizeof prefix) - 1;
1451
1452	if (ictx->flags & INPUT_DISCARD)
1453		return (0);
1454
1455	log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1456
1457	/* Check for tmux prefix. */
1458	if (ictx->input_len >= prefix_len &&
1459	    strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
1460		screen_write_rawstring(&ictx->ctx,
1461		    ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
1462	}
1463
1464	return (0);
1465}
1466
1467/* OSC string started. */
1468void
1469input_enter_osc(struct input_ctx *ictx)
1470{
1471	log_debug("%s", __func__);
1472
1473	input_clear(ictx);
1474}
1475
1476/* OSC terminator (ST) received. */
1477void
1478input_exit_osc(struct input_ctx *ictx)
1479{
1480	u_char *p = ictx->input_buf;
1481	int	option;
1482
1483	if (ictx->flags & INPUT_DISCARD)
1484		return;
1485	if (ictx->input_len < 1 || *p < '0' || *p > '9')
1486		return;
1487
1488	log_debug("%s: \"%s\"", __func__, p);
1489
1490	option = 0;
1491	while (*p >= '0' && *p <= '9')
1492		option = option * 10 + *p++ - '0';
1493	if (*p == ';')
1494		p++;
1495
1496	switch (option) {
1497	case 0:
1498	case 2:
1499		screen_set_title(ictx->ctx.s, p);
1500		server_status_window(ictx->wp->window);
1501		break;
1502	case 12:
1503		screen_set_cursor_colour(ictx->ctx.s, p);
1504		break;
1505	case 112:
1506		if (*p == '\0') /* No arguments allowed. */
1507			screen_set_cursor_colour(ictx->ctx.s, "");
1508		break;
1509	default:
1510		log_debug("%s: unknown '%u'", __func__, option);
1511		break;
1512	}
1513}
1514
1515/* APC string started. */
1516void
1517input_enter_apc(struct input_ctx *ictx)
1518{
1519	log_debug("%s", __func__);
1520
1521	input_clear(ictx);
1522}
1523
1524/* APC terminator (ST) received. */
1525void
1526input_exit_apc(struct input_ctx *ictx)
1527{
1528	if (ictx->flags & INPUT_DISCARD)
1529		return;
1530	log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1531
1532	screen_set_title(ictx->ctx.s, ictx->input_buf);
1533	server_status_window(ictx->wp->window);
1534}
1535
1536/* Rename string started. */
1537void
1538input_enter_rename(struct input_ctx *ictx)
1539{
1540	log_debug("%s", __func__);
1541
1542	input_clear(ictx);
1543}
1544
1545/* Rename terminator (ST) received. */
1546void
1547input_exit_rename(struct input_ctx *ictx)
1548{
1549	if (ictx->flags & INPUT_DISCARD)
1550		return;
1551	if (!options_get_number(&ictx->wp->window->options, "allow-rename"))
1552		return;
1553	log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1554
1555	xfree(ictx->wp->window->name);
1556	ictx->wp->window->name = xstrdup(ictx->input_buf);
1557	options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
1558
1559	server_status_window(ictx->wp->window);
1560}
1561
1562/* Open UTF-8 character. */
1563int
1564input_utf8_open(struct input_ctx *ictx)
1565{
1566	if (!options_get_number(&ictx->wp->window->options, "utf8")) {
1567		/* Print, and do not switch state. */
1568		input_print(ictx);
1569		return (-1);
1570	}
1571	log_debug("%s", __func__);
1572
1573	utf8_open(&ictx->utf8data, ictx->ch);
1574	return (0);
1575}
1576
1577/* Append to UTF-8 character. */
1578int
1579input_utf8_add(struct input_ctx *ictx)
1580{
1581	log_debug("%s", __func__);
1582
1583	utf8_append(&ictx->utf8data, ictx->ch);
1584	return (0);
1585}
1586
1587/* Close UTF-8 string. */
1588int
1589input_utf8_close(struct input_ctx *ictx)
1590{
1591	log_debug("%s", __func__);
1592
1593	utf8_append(&ictx->utf8data, ictx->ch);
1594
1595	ictx->cell.flags |= GRID_FLAG_UTF8;
1596	screen_write_cell(&ictx->ctx, &ictx->cell, &ictx->utf8data);
1597	ictx->cell.flags &= ~GRID_FLAG_UTF8;
1598
1599	return (0);
1600}
1601